From da487c4f31fd2d97c0d7110010e7379e5445ceb0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 15 Jun 2019 09:08:18 -0700 Subject: For now, short $_DFF_[NP]_ from ff_map.v at re-integration --- passes/techmap/abc9.cc | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index f7f2e862a..69b0c1192 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -511,6 +511,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri // Remove all AND, NOT, and ABC box instances // in preparation for stitching mapped_mod in + // Short $_DFF_[NP]_ cells used by ABC (FIXME) dict erased_boxes; for (auto it = module->cells_.begin(); it != module->cells_.end(); ) { RTLIL::Cell* cell = it->second; @@ -518,6 +519,13 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri it = module->cells_.erase(it); continue; } + else if (cell->type.in("$_DFF_N_", "$_DFF_P_")) { + SigBit D = cell->getPort("\\D"); + SigBit Q = cell->getPort("\\Q"); + module->connect(Q, D); + it = module->cells_.erase(it); + continue; + } RTLIL::Module* box_module = design->module(cell->type); if (box_module && box_module->attributes.count("\\abc_box_id")) { erased_boxes.insert(std::make_pair(it->first, std::move(cell->parameters))); -- cgit v1.2.3 From ac18a76bebad001fc3e617a7cefebe13610abcb8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 15 Jun 2019 09:34:48 -0700 Subject: Map to $_FF_ instead of $_DFF_P_ to prevent recursion issues --- passes/techmap/abc9.cc | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 69b0c1192..4bb4058b1 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -242,7 +242,7 @@ struct abc_output_filter }; void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, - bool cleanup, vector lut_costs, bool dff_mode, std::string clk_str, + bool cleanup, vector lut_costs, bool retime_mode, std::string clk_str, bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode, bool show_tempdir, std::string box_file, std::string lut_file, std::string wire_delay) @@ -285,7 +285,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0)); } - if (dff_mode && clk_sig.empty()) + if (retime_mode && clk_sig.empty()) log_cmd_error("Clock domain %s not found.\n", clk_str.c_str()); std::string tempdir_name = "/tmp/yosys-abc-XXXXXX"; @@ -359,7 +359,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri fprintf(f, "%s\n", abc_script.c_str()); fclose(f); - if (dff_mode || !clk_str.empty()) + if (retime_mode || !clk_str.empty()) { if (clk_sig.size() == 0) log("No%s clock domain found. Not extracting any FF cells.\n", clk_str.empty() ? "" : " matching"); @@ -511,7 +511,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri // Remove all AND, NOT, and ABC box instances // in preparation for stitching mapped_mod in - // Short $_DFF_[NP]_ cells used by ABC (FIXME) + // Short $_FF_ cells used by ABC (FIXME) dict erased_boxes; for (auto it = module->cells_.begin(); it != module->cells_.end(); ) { RTLIL::Cell* cell = it->second; @@ -519,7 +519,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri it = module->cells_.erase(it); continue; } - else if (cell->type.in("$_DFF_N_", "$_DFF_P_")) { + else if (cell->type.in("$_FF_")) { SigBit D = cell->getPort("\\D"); SigBit Q = cell->getPort("\\Q"); module->connect(Q, D); @@ -842,7 +842,7 @@ struct Abc9Pass : public Pass { #endif std::string script_file, clk_str, box_file, lut_file; std::string delay_target, lutin_shared = "-S 1", wire_delay; - bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true; + bool fast_mode = false, retime_mode = false, keepff = false, cleanup = true; bool show_tempdir = false; vector lut_costs; markgroups = false; @@ -933,13 +933,13 @@ struct Abc9Pass : public Pass { fast_mode = true; continue; } - //if (arg == "-dff") { - // dff_mode = true; - // continue; - //} + if (arg == "-retime") { + retime_mode = true; + continue; + } //if (arg == "-clk" && argidx+1 < args.size()) { // clk_str = args[++argidx]; - // dff_mode = true; + // retime_mode = true; // continue; //} //if (arg == "-keepff") { @@ -1003,8 +1003,8 @@ struct Abc9Pass : public Pass { } } - if (!dff_mode || !clk_str.empty()) { - abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, dff_mode, clk_str, keepff, + if (!retime_mode || !clk_str.empty()) { + abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, retime_mode, clk_str, keepff, delay_target, lutin_shared, fast_mode, show_tempdir, box_file, lut_file, wire_delay); continue; -- cgit v1.2.3 From a76c8a7ffdfb879971c8c3d1b1f7e8392ddf2c91 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 15 Jun 2019 09:46:35 -0700 Subject: Fix initialisation of flops --- passes/techmap/abc9.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 4bb4058b1..51bea4d57 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -520,8 +520,9 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri continue; } else if (cell->type.in("$_FF_")) { - SigBit D = cell->getPort("\\D"); - SigBit Q = cell->getPort("\\Q"); + RTLIL::Wire *D = cell->getPort("\\D").as_wire(); + RTLIL::Wire *Q = cell->getPort("\\Q").as_wire(); + Q->attributes.swap(D->attributes); module->connect(Q, D); it = module->cells_.erase(it); continue; -- cgit v1.2.3 From c2f3f116d041b97b0d8b6ed28c87810bf6c2630e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 15 Jun 2019 18:16:14 -0700 Subject: Use $__ABC_FF_ instead of $_FF_ --- passes/techmap/abc9.cc | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 51bea4d57..cedbc9273 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -399,6 +399,9 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri //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); +#if 0 + Pass::call(design, stringf("write_verilog -noexpr -norename %s/before.xaig", tempdir_name.c_str())); +#endif Pass::call(design, stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str())); std::string buffer; @@ -513,25 +516,22 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri // in preparation for stitching mapped_mod in // Short $_FF_ cells used by ABC (FIXME) dict erased_boxes; + std::vector abc_dff; for (auto it = module->cells_.begin(); it != module->cells_.end(); ) { RTLIL::Cell* cell = it->second; if (cell->type.in("$_AND_", "$_NOT_")) { it = module->cells_.erase(it); continue; } - else if (cell->type.in("$_FF_")) { - RTLIL::Wire *D = cell->getPort("\\D").as_wire(); - RTLIL::Wire *Q = cell->getPort("\\Q").as_wire(); - Q->attributes.swap(D->attributes); - module->connect(Q, D); - it = module->cells_.erase(it); - continue; - } - RTLIL::Module* box_module = design->module(cell->type); - if (box_module && box_module->attributes.count("\\abc_box_id")) { - erased_boxes.insert(std::make_pair(it->first, std::move(cell->parameters))); - it = module->cells_.erase(it); - continue; + if (cell->type.in("$__ABC_FF_")) + abc_dff.emplace_back(cell); + else { + RTLIL::Module* box_module = design->module(cell->type); + if (box_module && box_module->attributes.count("\\abc_box_id")) { + erased_boxes.insert(std::make_pair(it->first, std::move(cell->parameters))); + it = module->cells_.erase(it); + continue; + } } ++it; } @@ -671,6 +671,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri int in_wires = 0, out_wires = 0; // Stitch in mapped_mod's inputs/outputs into module + // TODO: iterate using ports for (auto &it : mapped_mod->wires_) { RTLIL::Wire *w = it.second; if (!w->port_input && !w->port_output) @@ -697,6 +698,13 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri } } + for (auto cell : abc_dff) { + RTLIL::SigBit D = cell->getPort("\\D"); + RTLIL::SigBit Q = cell->getPort("\\Q"); + module->connect(Q, D); + module->remove(cell); + } + //log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires); log("ABC RESULTS: input signals: %8d\n", in_wires); log("ABC RESULTS: output signals: %8d\n", out_wires); -- cgit v1.2.3 From cdfb634977b3ee005c5635f7902ea21dd45f7311 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 15 Jun 2019 18:18:56 -0700 Subject: Cleanup --- passes/techmap/abc9.cc | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index cedbc9273..e13cd0eef 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -671,26 +671,23 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri int in_wires = 0, out_wires = 0; // Stitch in mapped_mod's inputs/outputs into module - // TODO: iterate using ports - for (auto &it : mapped_mod->wires_) { - RTLIL::Wire *w = it.second; - if (!w->port_input && !w->port_output) - continue; - RTLIL::Wire *wire = module->wire(w->name); + for (auto port_name : mapped_mod->ports) { + RTLIL::Wire *port = mapped_mod->wire(port_name); + log_assert(port); + RTLIL::Wire *wire = module->wire(port->name); log_assert(wire); - RTLIL::Wire *remap_wire = module->wire(remap_name(w->name)); + RTLIL::Wire *remap_wire = module->wire(remap_name(port->name)); RTLIL::SigSpec signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire)); log_assert(GetSize(signal) >= GetSize(remap_wire)); - log_assert(w->port_input || w->port_output); RTLIL::SigSig conn; - if (w->port_input) { + if (port->port_input) { conn.first = remap_wire; conn.second = signal; in_wires++; module->connect(conn); } - if (w->port_output) { + if (port->port_output) { conn.first = signal; conn.second = remap_wire; out_wires++; -- cgit v1.2.3 From 2309459605b262040f7bea84e6d935d2838686d5 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 15 Jun 2019 19:36:55 -0700 Subject: Do not treat $__ABC_FF_ as a user cell --- passes/techmap/abc9.cc | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index e13cd0eef..decf5a6aa 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -512,26 +512,18 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri } } - // Remove all AND, NOT, and ABC box instances - // in preparation for stitching mapped_mod in - // Short $_FF_ cells used by ABC (FIXME) dict erased_boxes; - std::vector abc_dff; for (auto it = module->cells_.begin(); it != module->cells_.end(); ) { RTLIL::Cell* cell = it->second; - if (cell->type.in("$_AND_", "$_NOT_")) { + if (cell->type.in("$_AND_", "$_NOT_", "$__ABC_FF_")) { it = module->cells_.erase(it); continue; } - if (cell->type.in("$__ABC_FF_")) - abc_dff.emplace_back(cell); - else { - RTLIL::Module* box_module = design->module(cell->type); - if (box_module && box_module->attributes.count("\\abc_box_id")) { - erased_boxes.insert(std::make_pair(it->first, std::move(cell->parameters))); - it = module->cells_.erase(it); - continue; - } + RTLIL::Module* box_module = design->module(cell->type); + if (box_module && box_module->attributes.count("\\abc_box_id")) { + erased_boxes.insert(std::make_pair(it->first, std::move(cell->parameters))); + it = module->cells_.erase(it); + continue; } ++it; } @@ -695,13 +687,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri } } - for (auto cell : abc_dff) { - RTLIL::SigBit D = cell->getPort("\\D"); - RTLIL::SigBit Q = cell->getPort("\\Q"); - module->connect(Q, D); - module->remove(cell); - } - //log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires); log("ABC RESULTS: input signals: %8d\n", in_wires); log("ABC RESULTS: output signals: %8d\n", out_wires); -- cgit v1.2.3 From 416312b9ed027b062c4e043b6265b73b25eb299a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 15 Jun 2019 22:44:45 -0700 Subject: abc9 to recover_init by default --- passes/techmap/abc9.cc | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index decf5a6aa..aea5e478d 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -67,7 +67,6 @@ SigMap assign_map; RTLIL::Module *module; std::map signal_map; std::map signal_init; -bool recover_init; bool clk_polarity, en_polarity; RTLIL::SigSpec clk_sig, en_sig; @@ -253,7 +252,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri signal_map.clear(); pi_map.clear(); po_map.clear(); - recover_init = false; if (clk_str != "$") { @@ -510,6 +508,12 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri for (int i = 0; i < GetSize(wire); i++) output_bits.insert({wire, i}); } + + auto jt = w->attributes.find("\\init"); + if (jt != w->attributes.end()) { + auto r = remap_wire->attributes.insert(std::make_pair("\\init", jt->second)); + log_assert(r.second); + } } dict erased_boxes; @@ -649,15 +653,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri module->connect(conn); } - if (recover_init) - for (auto wire : mapped_mod->wires()) { - if (wire->attributes.count("\\init")) { - Wire *w = module->wires_[remap_name(wire->name)]; - log_assert(w->attributes.count("\\init") == 0); - w->attributes["\\init"] = wire->attributes.at("\\init"); - } - } - for (auto &it : cell_stats) log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second); int in_wires = 0, out_wires = 0; -- cgit v1.2.3 From 3ed95dae8d7661256003f5294f6aa7168b87c5a8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 15 Jun 2019 22:48:16 -0700 Subject: Cleanup --- passes/techmap/abc9.cc | 47 +++++++---------------------------------------- 1 file changed, 7 insertions(+), 40 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index aea5e478d..4e7bdfa8f 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -65,12 +65,9 @@ bool markgroups; int map_autoidx; SigMap assign_map; RTLIL::Module *module; -std::map signal_map; -std::map signal_init; bool clk_polarity, en_polarity; RTLIL::SigSpec clk_sig, en_sig; -dict pi_map, po_map; std::string remap_name(RTLIL::IdString abc_name) { @@ -227,13 +224,13 @@ struct abc_output_filter void next_line(const std::string &line) { - int pi, po; - if (sscanf(line.c_str(), "Start-point = pi%d. End-point = po%d.", &pi, &po) == 2) { - log("ABC: Start-point = pi%d (%s). End-point = po%d (%s).\n", - pi, pi_map.count(pi) ? pi_map.at(pi).c_str() : "???", - po, po_map.count(po) ? po_map.at(po).c_str() : "???"); - return; - } + //int pi, po; + //if (sscanf(line.c_str(), "Start-point = pi%d. End-point = po%d.", &pi, &po) == 2) { + // log("ABC: Start-point = pi%d (%s). End-point = po%d (%s).\n", + // pi, pi_map.count(pi) ? pi_map.at(pi).c_str() : "???", + // po, po_map.count(po) ? po_map.at(po).c_str() : "???"); + // return; + //} for (char ch : line) next_char(ch); @@ -249,10 +246,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri module = current_module; map_autoidx = autoidx++; - signal_map.clear(); - pi_map.clear(); - po_map.clear(); - if (clk_str != "$") { clk_polarity = true; @@ -816,10 +809,6 @@ struct Abc9Pass : public Pass { log_push(); assign_map.clear(); - signal_map.clear(); - signal_init.clear(); - pi_map.clear(); - po_map.clear(); #ifdef ABCEXTERNAL std::string exe_file = ABCEXTERNAL; @@ -970,24 +959,6 @@ struct Abc9Pass : public Pass { } assign_map.set(mod); - signal_init.clear(); - - for (Wire *wire : mod->wires()) - if (wire->attributes.count("\\init")) { - SigSpec initsig = assign_map(wire); - Const initval = wire->attributes.at("\\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::S0; - break; - default: - break; - } - } if (!retime_mode || !clk_str.empty()) { abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, retime_mode, clk_str, keepff, @@ -1146,10 +1117,6 @@ struct Abc9Pass : public Pass { Pass::call(design, "clean"); assign_map.clear(); - signal_map.clear(); - signal_init.clear(); - pi_map.clear(); - po_map.clear(); log_pop(); } -- cgit v1.2.3 From d80678e581899315791706ee1703bf700b0f9c15 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 17 Jun 2019 15:10:33 -0700 Subject: Cleanup --- passes/techmap/abc9.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 776bceb3b..f56350b1d 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -527,7 +527,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri } RTLIL::Module* box_module = design->module(cell->type); if (box_module && box_module->attributes.count("\\abc_box_id")) - boxes.emplace_back(it->second); + boxes.emplace_back(cell); ++it; } @@ -629,8 +629,8 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri } } - for (auto cell : boxes) - module->remove(cell); + for (auto cell : boxes) + module->remove(cell); // Copy connections (and rename) from mapped_mod to module for (auto conn : mapped_mod->connections()) { -- cgit v1.2.3 From ef757002dbc8280a65d25618e57b20d3dbadd64a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 1 Jul 2019 10:55:24 -0700 Subject: Also remove $__ABC_FF_ --- passes/techmap/abc9.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 2eee43739..30df8e3ef 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -566,7 +566,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri vector boxes; for (const auto &it : module->cells_) { auto cell = it.second; - if (cell->type.in("$_AND_", "$_NOT_")) { + if (cell->type.in("$_AND_", "$_NOT_", "$__ABC_FF_")) { module->remove(cell); continue; } -- cgit v1.2.3 From 71acd3ddcfc9083f23ee624de1c16be6b8dbe4d6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 10 Jul 2019 18:57:44 -0700 Subject: Remove -retime from abc9, revert to abc behav with separate clock/en domains --- passes/techmap/abc9.cc | 90 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 29 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 30df8e3ef..6e57ab7f3 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -285,7 +285,7 @@ struct abc_output_filter }; void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, - bool cleanup, vector lut_costs, bool retime_mode, std::string clk_str, + bool cleanup, vector lut_costs, bool /*retime_mode*/, std::string clk_str, bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode, bool show_tempdir, std::string box_file, std::string lut_file, std::string wire_delay) @@ -323,8 +323,8 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0)); } - if (retime_mode && clk_sig.empty()) - log_cmd_error("Clock domain %s not found.\n", clk_str.c_str()); + //if (retime_mode && clk_sig.empty()) + // log_cmd_error("Clock domain %s not found.\n", clk_str.c_str()); std::string tempdir_name = "/tmp/yosys-abc-XXXXXX"; if (!cleanup) @@ -397,7 +397,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri fprintf(f, "%s\n", abc_script.c_str()); fclose(f); - if (retime_mode || !clk_str.empty()) + if (/*retime_mode ||*/ !clk_str.empty()) { if (clk_sig.size() == 0) log("No%s clock domain found. Not extracting any FF cells.\n", clk_str.empty() ? "" : " matching"); @@ -874,7 +874,7 @@ struct Abc9Pass : public Pass { #endif std::string script_file, clk_str, box_file, lut_file; std::string delay_target, lutin_shared = "-S 1", wire_delay; - bool fast_mode = false, retime_mode = false, keepff = false, cleanup = true; + bool fast_mode = false, /*retime_mode = false,*/ keepff = false, cleanup = true; bool show_tempdir = false; vector lut_costs; markgroups = false; @@ -965,10 +965,10 @@ struct Abc9Pass : public Pass { fast_mode = true; continue; } - if (arg == "-retime") { - retime_mode = true; - continue; - } + //if (arg == "-retime") { + // retime_mode = true; + // continue; + //} //if (arg == "-clk" && argidx+1 < args.size()) { // clk_str = args[++argidx]; // retime_mode = true; @@ -1017,13 +1017,6 @@ struct Abc9Pass : public Pass { assign_map.set(mod); - if (!retime_mode || !clk_str.empty()) { - abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, retime_mode, clk_str, keepff, - delay_target, lutin_shared, fast_mode, show_tempdir, - box_file, lut_file, wire_delay); - continue; - } - CellTypes ct(design); std::vector all_cells = mod->selected_cells(); @@ -1040,8 +1033,10 @@ struct Abc9Pass : public Pass { std::map> cell_to_bit, cell_to_bit_up, cell_to_bit_down; std::map> bit_to_cell, bit_to_cell_up, bit_to_cell_down; - for (auto cell : all_cells) - { + pool seen_cells; + dict> flop_data; + + for (auto cell : all_cells) { clkdomain_t key; for (auto &conn : cell->connections()) @@ -1061,19 +1056,56 @@ struct Abc9Pass : public Pass { } } - if (cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_") - { - key = clkdomain_t(cell->type == "$_DFF_P_", assign_map(cell->getPort("\\C")), true, RTLIL::SigSpec()); + decltype(flop_data)::iterator it; + if (seen_cells.insert(cell->type).second) { + RTLIL::Module* inst_module = design->module(cell->type); + if (!inst_module) + continue; + + if (!inst_module->attributes.count("\\abc_flop")) + continue; + + IdString abc_flop_clk, abc_flop_en; + for (auto port_name : inst_module->ports) { + auto wire = inst_module->wire(port_name); + log_assert(wire); + if (wire->attributes.count("\\abc_flop_clk")) { + if (abc_flop_clk != IdString()) + log_error("More than one port has the 'abc_flop_clk' attribute set on module '%s'.\n", log_id(cell->type)); + abc_flop_clk = port_name; + } + if (wire->attributes.count("\\abc_flop_en")) { + if (abc_flop_en != IdString()) + log_error("More than one port has the 'abc_flop_en' attribute set on module '%s'.\n", log_id(cell->type)); + abc_flop_en = port_name; + } + } + + if (abc_flop_clk == IdString()) + log_error("'abc_flop_clk' attribute not found on any ports on module '%s'.\n", log_id(cell->type)); + if (abc_flop_en == IdString()) + log_error("'abc_flop_en' attribute not found on any ports on module '%s'.\n", log_id(cell->type)); + it = flop_data.insert(std::make_pair(cell->type, std::make_pair(abc_flop_clk, abc_flop_en))).first; } - 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 { + it = flop_data.find(cell->type); + if (it == flop_data.end()) + continue; } - else - continue; + + auto jt = cell->parameters.find("\\$abc_flop_clk_pol"); + if (jt == cell->parameters.end()) + log_error("'$abc_flop_clk_pol' parameter not found on module '%s'.\n", log_id(cell->type)); + cell->parameters.erase(jt); + bool this_clk_pol = jt->second.as_bool(); + jt = cell->parameters.find("\\$abc_flop_en_pol"); + if (jt == cell->parameters.end()) + log_error("'$abc_flop_en_pol' parameter not found on module '%s'.\n", log_id(cell->type)); + bool this_en_pol = jt->second.as_bool(); + cell->parameters.erase(jt); + + const auto &data = it->second; + key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(data.first)), this_en_pol, assign_map(cell->getPort(data.second))); unassigned_cells.erase(cell); expand_queue.insert(cell); -- cgit v1.2.3 From 9f608d6be30c9302c0e3810525457e39f57b0334 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 10 Jul 2019 20:25:59 -0700 Subject: write_verilog with *.v extension --- passes/techmap/abc9.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 6e57ab7f3..330361f65 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -435,7 +435,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri // count_gates, GetSize(signal_list), count_input, count_output); #if 0 - Pass::call(design, stringf("write_verilog -noexpr -norename %s/before.xaig", tempdir_name.c_str())); + Pass::call(design, stringf("write_verilog -noexpr -norename %s/before.v", tempdir_name.c_str())); #endif Pass::call(design, stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str())); -- cgit v1.2.3 From 33862d04451ba58ce2b51c1e11abf86b65c3f018 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 11 Jul 2019 09:22:52 -0700 Subject: WIP for fixing partitioning, temporarily do not partition --- passes/techmap/abc9.cc | 46 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 330361f65..4347c3789 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -86,7 +86,7 @@ void handle_loops(RTLIL::Design *design) // cell in the component, and select (and mark) all its output // wires pool ids_seen; - for (auto cell : module->cells()) { + for (auto cell : module->selected_cells()) { auto it = cell->attributes.find("\\abc_scc_id"); if (it != cell->attributes.end()) { auto r = ids_seen.insert(it->second); @@ -423,10 +423,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri if (count_output) { - design->selection_stack.emplace_back(false); - RTLIL::Selection& sel = design->selection_stack.back(); - sel.select(module); - Pass::call(design, "aigmap"); handle_loops(design); @@ -457,8 +453,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri design->remove(design->module("$__abc9__")); #endif - design->selection_stack.pop_back(); - // Now 'unexpose' those wires by undoing // the expose operation -- remove them from PO/PI // and re-connecting them back together @@ -477,7 +471,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri } module->fixup_ports(); - log_header(design, "Executing ABC9.\n"); if (!lut_costs.empty()) { @@ -564,8 +557,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri dict abc_box; vector boxes; - for (const auto &it : module->cells_) { - auto cell = it.second; + for (auto cell : module->selected_cells()) { if (cell->type.in("$_AND_", "$_NOT_", "$__ABC_FF_")) { module->remove(cell); continue; @@ -663,6 +655,13 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri if (existing_cell) { cell->parameters = existing_cell->parameters; cell->attributes = existing_cell->attributes; + + auto it = cell->parameters.find("\\$abc_flop_clk_pol"); + if (it != cell->parameters.end()) + cell->parameters.erase(it); + it = cell->parameters.find("\\$abc_flop_en_pol"); + if (it != cell->parameters.end()) + cell->parameters.erase(it); } else { cell->parameters = c->parameters; @@ -1017,6 +1016,20 @@ struct Abc9Pass : public Pass { assign_map.set(mod); + if (true || /*!dff_mode ||*/ !clk_str.empty()) { + + design->selection_stack.emplace_back(false); + RTLIL::Selection& sel = design->selection_stack.back(); + sel.select(mod); + + abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, false, clk_str, keepff, + delay_target, lutin_shared, fast_mode, show_tempdir, + box_file, lut_file, wire_delay); + + design->selection_stack.pop_back(); + continue; + } + CellTypes ct(design); std::vector all_cells = mod->selected_cells(); @@ -1096,13 +1109,11 @@ struct Abc9Pass : public Pass { auto jt = cell->parameters.find("\\$abc_flop_clk_pol"); if (jt == cell->parameters.end()) log_error("'$abc_flop_clk_pol' parameter not found on module '%s'.\n", log_id(cell->type)); - cell->parameters.erase(jt); bool this_clk_pol = jt->second.as_bool(); jt = cell->parameters.find("\\$abc_flop_en_pol"); if (jt == cell->parameters.end()) log_error("'$abc_flop_en_pol' parameter not found on module '%s'.\n", log_id(cell->type)); bool this_en_pol = jt->second.as_bool(); - cell->parameters.erase(jt); const auto &data = it->second; key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(data.first)), this_en_pol, assign_map(cell->getPort(data.second))); @@ -1191,16 +1202,27 @@ struct Abc9Pass : public Pass { std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)), std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first))); + design->selection_stack.emplace_back(false); + RTLIL::Selection& sel = design->selection_stack.back(); + 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)); + + pool assigned_names; + for (auto i : it.second) + assigned_names.insert(i->name); + sel.selected_members[mod->name] = std::move(assigned_names); + abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, !clk_sig.empty(), "$", keepff, delay_target, lutin_shared, fast_mode, show_tempdir, box_file, lut_file, wire_delay); assign_map.set(mod); } + + design->selection_stack.pop_back(); } Pass::call(design, "clean"); -- cgit v1.2.3 From 0c3ed73dade2488d0add1a3e6e82b148171f2d66 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 11 Jul 2019 09:55:14 -0700 Subject: Count $_NOT_ cells turned into $luts --- passes/techmap/abc9.cc | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 4347c3789..53b0b8bbe 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -584,7 +584,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri log_assert(wire); module->connect(RTLIL::SigBit(wire, y_bit.offset), RTLIL::S1); } - else if (!lut_costs.empty() || !lut_file.empty()) { + else { RTLIL::Cell* driving_lut = nullptr; // ABC can return NOT gates that drive POs if (!a_bit.wire->port_input) { @@ -622,12 +622,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset), driver_lut); } - } - else { - cell = module->addCell(remap_name(c->name), "$_NOT_"); - cell->setPort("\\A", RTLIL::SigBit(module->wires_[remap_name(a_bit.wire->name)], a_bit.offset)); - cell->setPort("\\Y", RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset)); - cell_stats[RTLIL::unescape_id(c->type)]++; + cell_stats["$lut"]++; } if (cell && markgroups) cell->attributes["\\abcgroup"] = map_autoidx; continue; -- cgit v1.2.3 From 237d8651a5b91bf4fa1de69d0930fdcbba049e40 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 11 Jul 2019 09:58:00 -0700 Subject: Error out if abc9 not called with -lut or -luts --- passes/techmap/abc9.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 53b0b8bbe..b9eb71cf1 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -999,6 +999,9 @@ struct Abc9Pass : public Pass { } extra_args(args, argidx, design); + if (lut_costs.empty() && lut_file.empty()) + log_cmd_error("abc9 must be called with '-lut' or '-luts'\n"); + for (auto mod : design->selected_modules()) { if (mod->attributes.count("\\abc_box_id")) -- cgit v1.2.3 From dd59375a66b6463df9cc371b30249324b47399aa Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 15 Jul 2019 14:46:31 -0700 Subject: Add xilinx_dsp for register packing --- passes/pmgen/.gitignore | 3 +- passes/pmgen/xilinx_dsp.cc | 120 ++++++++++++++++++++++++++++++++++++++++++++ passes/pmgen/xilinx_dsp.pmg | 71 ++++++++++++++++++++++++++ 3 files changed, 192 insertions(+), 2 deletions(-) create mode 100644 passes/pmgen/xilinx_dsp.cc create mode 100644 passes/pmgen/xilinx_dsp.pmg (limited to 'passes') diff --git a/passes/pmgen/.gitignore b/passes/pmgen/.gitignore index 0ad36ea2c..10e245e00 100644 --- a/passes/pmgen/.gitignore +++ b/passes/pmgen/.gitignore @@ -1,2 +1 @@ -/ice40_dsp_pm.h -/peepopt_pm.h +/%_pm.h diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc new file mode 100644 index 000000000..b98703de3 --- /dev/null +++ b/passes/pmgen/xilinx_dsp.cc @@ -0,0 +1,120 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * 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 + +#include "passes/pmgen/xilinx_dsp_pm.h" + +void create_xilinx_dsp(xilinx_dsp_pm &pm) +{ + auto &st = pm.st_xilinx_dsp; + +#if 0 + log("\n"); + log("ffA: %s\n", log_id(st.ffA, "--")); + log("ffB: %s\n", log_id(st.ffB, "--")); + log("mul: %s\n", log_id(st.mul, "--")); + log("ffY: %s\n", log_id(st.ffY, "--")); +#endif + + log("Analysing %s.%s for Xilinx DSP register packing.\n", log_id(pm.module), log_id(st.mul)); + + Cell *cell = st.mul; + log_assert(cell); + + // Input Interface + + cell->setPort("\\A", st.sigA); + cell->setPort("\\B", st.sigB); + + cell->setParam("\\AREG", st.ffA ? State::S1 : State::S0); + cell->setParam("\\BREG", st.ffB ? State::S1 : State::S0); + + if (st.clock != SigBit()) + { + cell->setPort("\\CLK", st.clock); + + if (st.ffA) { + cell->setParam("\\AREG", State::S1); + cell->setPort("\\CEA2", State::S1); + } + if (st.ffB) { + cell->setParam("\\BREG", State::S1); + cell->setPort("\\CEA2", State::S1); + } + if (st.ffY) { + cell->setPort("\\PREG", State::S1); + cell->setPort("\\CEP", State::S1); + } + + log(" clock: %s (%s)", log_signal(st.clock), "posedge"); + + if (st.ffA) + log(" ffA:%s", log_id(st.ffA)); + + if (st.ffB) + log(" ffB:%s", log_id(st.ffB)); + + if (st.ffY) + log(" ffY:%s", log_id(st.ffY)); + + log("\n"); + } + + // Output Interface + + pm.autoremove(st.ffY); +} + +struct Ice40DspPass : public Pass { + Ice40DspPass() : Pass("xilinx_dsp", "Xilinx: pack DSP registers") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" xilinx_dsp [options] [selection]\n"); + log("\n"); + log("Pack registers into Xilinx DSPs\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing ICE40_DSP pass (map multipliers).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-singleton") { + // singleton_mode = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + xilinx_dsp_pm(module, module->selected_cells()).run_xilinx_dsp(create_xilinx_dsp); + } +} Ice40DspPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg new file mode 100644 index 000000000..6bb4e7bd8 --- /dev/null +++ b/passes/pmgen/xilinx_dsp.pmg @@ -0,0 +1,71 @@ +pattern xilinx_dsp + +state clock +state sigA sigB sigY sigS +state addAB muxAB + +match mul + select mul->type.in($__MUL25X18) +endmatch + +match ffA + select ffA->type.in($dff) /* TODO: $dffe */ + // select nusers(port(ffA, \Q)) == 2 + index port(ffA, \Q) === port(mul, \A) + // DSP48E1 does not support clock inversion + index port(ffA, \CLK_POLARITY) === State::S1 + optional +endmatch + +code sigA clock + sigA = port(mul, \A); + + if (ffA) { + sigA = port(ffA, \D); + clock = port(ffA, \CLK).as_bit(); + } +endcode + +match ffB + select ffB->type.in($dff) + // select nusers(port(ffB, \Q)) == 2 + index port(ffB, \Q) === port(mul, \B) + index port(ffB, \CLK_POLARITY) === State::S1 + optional +endmatch + +code sigB clock + sigB = port(mul, \B); + + if (ffB) { + sigB = port(ffB, \D); + SigBit c = port(ffB, \CLK).as_bit(); + + if (clock != SigBit() && c != clock) + reject; + + clock = c; + } +endcode + +match ffY + select ffY->type.in($dff) + select nusers(port(ffY, \D)) == 2 + index port(ffY, \D) === port(mul, \Y) + index port(ffY, \CLK_POLARITY) === State::S1 + optional +endmatch + +code sigY clock + sigY = port(mul, \Y); + + if (ffY) { + sigY = port(ffY, \Q); + SigBit c = port(ffY, \CLK).as_bit(); + + if (clock != SigBit() && c != clock) + reject; + + clock = c; + } +endcode -- cgit v1.2.3 From 5f00d335d4861fc03dd7b6cee68fd79505bd3d41 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 15 Jul 2019 15:03:15 -0700 Subject: Oops forgot these files --- passes/pmgen/Makefile.inc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index 7911132db..e33866670 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -1,14 +1,19 @@ OBJS += passes/pmgen/ice40_dsp.o +OBJS += passes/pmgen/xilinx_dsp.o OBJS += passes/pmgen/peepopt.o # -------------------------------------- +passes/pmgen/%.o: passes/pmgen/%_pm.h passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h +passes/pmgen/xilinx_dsp.o: passes/pmgen/xilinx_dsp_pm.h EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h +EXTRA_OBJS += passes/pmgen/xilinx_dsp_pm.h .SECONDARY: passes/pmgen/ice40_dsp_pm.h +.SECONDARY: passes/pmgen/xilinx_dsp_pm.h -passes/pmgen/ice40_dsp_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_dsp.pmg - $(P) mkdir -p passes/pmgen && python3 $< -o $@ -p ice40_dsp $(filter-out $<,$^) +passes/pmgen/%_pm.h: passes/pmgen/pmgen.py passes/pmgen/%.pmg + $(P) mkdir -p passes/pmgen && python3 $< -o $@ -p $* $(filter-out $<,$^) # -------------------------------------- -- cgit v1.2.3 From 9616dbd125171905bccf55fa7fd564e4ae2ca5ab Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 16 Jul 2019 14:06:32 -0700 Subject: Add support {A,B,P}REG packing --- passes/pmgen/xilinx_dsp.cc | 68 ++++++++++++++++++++++--------------- passes/pmgen/xilinx_dsp.pmg | 81 +++++++++++++++++++++++++++++---------------- 2 files changed, 94 insertions(+), 55 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index b98703de3..a09f96a7f 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -25,46 +25,60 @@ PRIVATE_NAMESPACE_BEGIN #include "passes/pmgen/xilinx_dsp_pm.h" -void create_xilinx_dsp(xilinx_dsp_pm &pm) +void pack_xilinx_dsp(xilinx_dsp_pm &pm) { auto &st = pm.st_xilinx_dsp; -#if 0 +#if 1 log("\n"); log("ffA: %s\n", log_id(st.ffA, "--")); log("ffB: %s\n", log_id(st.ffB, "--")); - log("mul: %s\n", log_id(st.mul, "--")); - log("ffY: %s\n", log_id(st.ffY, "--")); + log("dsp: %s\n", log_id(st.dsp, "--")); + log("ffP: %s\n", log_id(st.ffP, "--")); + log("muxP: %s\n", log_id(st.muxP, "--")); + log("P_WIDTH: %d\n", st.P_WIDTH); #endif - log("Analysing %s.%s for Xilinx DSP register packing.\n", log_id(pm.module), log_id(st.mul)); + log("Analysing %s.%s for Xilinx DSP register packing.\n", log_id(pm.module), log_id(st.dsp)); - Cell *cell = st.mul; + Cell *cell = st.dsp; log_assert(cell); - // Input Interface - - cell->setPort("\\A", st.sigA); - cell->setPort("\\B", st.sigB); - - cell->setParam("\\AREG", st.ffA ? State::S1 : State::S0); - cell->setParam("\\BREG", st.ffB ? State::S1 : State::S0); - if (st.clock != SigBit()) { cell->setPort("\\CLK", st.clock); if (st.ffA) { + SigSpec D = st.ffA->getPort("\\D"); + cell->setPort("\\A", D.extend_u0(30)); cell->setParam("\\AREG", State::S1); - cell->setPort("\\CEA2", State::S1); + if (st.ffA->type == "$dff") + cell->setPort("\\CEA2", State::S1); + else if (st.ffA->type == "$dffe") + cell->setPort("\\CEA2", st.ffA->getPort("\\EN")); + else log_abort(); } if (st.ffB) { + SigSpec D = st.ffB->getPort("\\D"); + cell->setPort("\\B", D.extend_u0(18)); cell->setParam("\\BREG", State::S1); - cell->setPort("\\CEA2", State::S1); + if (st.ffB->type == "$dff") + cell->setPort("\\CEB2", State::S1); + else if (st.ffB->type == "$dffe") + cell->setPort("\\CEB2", st.ffB->getPort("\\EN")); + else log_abort(); } - if (st.ffY) { - cell->setPort("\\PREG", State::S1); - cell->setPort("\\CEP", State::S1); + if (st.ffP) { + SigSpec P = cell->getPort("\\P"); + SigSpec Q = st.ffP->getPort("\\Q"); + Q.append(P.extract(GetSize(Q), -1)); + cell->setPort("\\P", Q); + cell->setParam("\\PREG", State::S1); + if (st.ffP->type == "$dff") + cell->setPort("\\CEP", State::S1); + else if (st.ffP->type == "$dffe") + cell->setPort("\\CEP", st.ffP->getPort("\\EN")); + else log_abort(); } log(" clock: %s (%s)", log_signal(st.clock), "posedge"); @@ -75,15 +89,17 @@ void create_xilinx_dsp(xilinx_dsp_pm &pm) if (st.ffB) log(" ffB:%s", log_id(st.ffB)); - if (st.ffY) - log(" ffY:%s", log_id(st.ffY)); + if (st.ffP) + log(" ffY:%s", log_id(st.ffP)); log("\n"); } - // Output Interface - - pm.autoremove(st.ffY); + pm.autoremove(st.ffA); + pm.autoremove(st.ffB); + pm.autoremove(st.ffP); + pm.autoremove(st.muxP); + pm.blacklist(cell); } struct Ice40DspPass : public Pass { @@ -99,7 +115,7 @@ struct Ice40DspPass : public Pass { } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { - log_header(design, "Executing ICE40_DSP pass (map multipliers).\n"); + log_header(design, "Executing XILINX_DSP pass (pack DSPs).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -113,7 +129,7 @@ struct Ice40DspPass : public Pass { extra_args(args, argidx, design); for (auto module : design->selected_modules()) - xilinx_dsp_pm(module, module->selected_cells()).run_xilinx_dsp(create_xilinx_dsp); + xilinx_dsp_pm(module, module->selected_cells()).run_xilinx_dsp(pack_xilinx_dsp); } } Ice40DspPass; diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 6bb4e7bd8..ceed64b30 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,44 +1,36 @@ pattern xilinx_dsp state clock -state sigA sigB sigY sigS -state addAB muxAB +state P_WIDTH -match mul - select mul->type.in($__MUL25X18) +match dsp + select dsp->type.in(\DSP48E1) endmatch match ffA - select ffA->type.in($dff) /* TODO: $dffe */ + select ffA->type.in($dff, $dffe) // select nusers(port(ffA, \Q)) == 2 - index port(ffA, \Q) === port(mul, \A) + index port(ffA, \Q).extend_u0(30) === port(dsp, \A) // DSP48E1 does not support clock inversion - index port(ffA, \CLK_POLARITY) === State::S1 + index param(ffA, \CLK_POLARITY).as_bool() === true optional endmatch -code sigA clock - sigA = port(mul, \A); - - if (ffA) { - sigA = port(ffA, \D); +code clock + if (ffA) clock = port(ffA, \CLK).as_bit(); - } endcode match ffB - select ffB->type.in($dff) + select ffB->type.in($dff, $dffe) // select nusers(port(ffB, \Q)) == 2 - index port(ffB, \Q) === port(mul, \B) - index port(ffB, \CLK_POLARITY) === State::S1 + index port(ffB, \Q).extend_u0(18) === port(dsp, \B) + index param(ffB, \CLK_POLARITY).as_bool() === true optional endmatch -code sigB clock - sigB = port(mul, \B); - +code clock if (ffB) { - sigB = port(ffB, \D); SigBit c = port(ffB, \CLK).as_bit(); if (clock != SigBit() && c != clock) @@ -48,20 +40,51 @@ code sigB clock } endcode +code P_WIDTH + SigSpec P = port(dsp, \P); + int i; + for (i = GetSize(P); i > 0; i--) + if (nusers(P[i-1]) > 1) + break; + P_WIDTH = i; +endcode + +match ffP + select ffP->type.in($dff, $dffe) + select nusers(port(ffP, \D)) == 2 + filter param(ffP, \WIDTH).as_int() == P_WIDTH + filter port(ffP, \D) == port(dsp, \P).extract(0, P_WIDTH) + index param(ffP, \CLK_POLARITY) === State::S1 + optional +endmatch + +// $mux cell left behind by dff2dffe +// would prefer not to run 'opt_expr -mux_undef' +// since that would lose information helpful for +// efficient wide-mux inference +match muxP + if !ffP + select muxP->type.in($mux) + select port(muxP, \A).is_fully_undef() + filter param(muxP, \WIDTH).as_int() == P_WIDTH + filter port(muxP, \B) == port(dsp, \P).extract(0, P_WIDTH) + select nusers(port(muxP, \B)) == 2 + optional +endmatch + match ffY - select ffY->type.in($dff) + if muxP + select ffY->type.in($dff, $dffe) select nusers(port(ffY, \D)) == 2 - index port(ffY, \D) === port(mul, \Y) - index port(ffY, \CLK_POLARITY) === State::S1 - optional + index port(ffY, \D) === port(muxP, \Y) endmatch -code sigY clock - sigY = port(mul, \Y); +code ffP clock + if (ffY) + ffP = ffY; - if (ffY) { - sigY = port(ffY, \Q); - SigBit c = port(ffY, \CLK).as_bit(); + if (ffP) { + SigBit c = port(ffP, \CLK).as_bit(); if (clock != SigBit() && c != clock) reject; -- cgit v1.2.3 From 3f677fb0db15f75d9655fe653f991c94e78a4a1f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 16 Jul 2019 15:54:07 -0700 Subject: Signed extension --- passes/pmgen/xilinx_dsp.cc | 4 ++-- passes/pmgen/xilinx_dsp.pmg | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index a09f96a7f..a4602dd63 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -50,7 +50,7 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) if (st.ffA) { SigSpec D = st.ffA->getPort("\\D"); - cell->setPort("\\A", D.extend_u0(30)); + cell->setPort("\\A", D.extend_u0(30, true)); cell->setParam("\\AREG", State::S1); if (st.ffA->type == "$dff") cell->setPort("\\CEA2", State::S1); @@ -60,7 +60,7 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) } if (st.ffB) { SigSpec D = st.ffB->getPort("\\D"); - cell->setPort("\\B", D.extend_u0(18)); + cell->setPort("\\B", D.extend_u0(18, true)); cell->setParam("\\BREG", State::S1); if (st.ffB->type == "$dff") cell->setPort("\\CEB2", State::S1); diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index ceed64b30..4b7bea308 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -9,10 +9,10 @@ endmatch match ffA select ffA->type.in($dff, $dffe) + select param(ffA, \CLK_POLARITY).as_bool() // select nusers(port(ffA, \Q)) == 2 - index port(ffA, \Q).extend_u0(30) === port(dsp, \A) + index port(ffA, \Q).extend_u0(25, true) === port(dsp, \A).extract(0, 25) // DSP48E1 does not support clock inversion - index param(ffA, \CLK_POLARITY).as_bool() === true optional endmatch @@ -23,9 +23,9 @@ endcode match ffB select ffB->type.in($dff, $dffe) + select param(ffB, \CLK_POLARITY).as_bool() // select nusers(port(ffB, \Q)) == 2 - index port(ffB, \Q).extend_u0(18) === port(dsp, \B) - index param(ffB, \CLK_POLARITY).as_bool() === true + index port(ffB, \Q).extend_u0(18, true) === port(dsp, \B) optional endmatch -- cgit v1.2.3 From 91629ee4b3aae3aa8243a659ffe1716ad5c432a2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 17 Jul 2019 12:45:25 -0700 Subject: Pattern matcher to check pool of bits, not exactly --- passes/pmgen/xilinx_dsp.cc | 12 +++++++++--- passes/pmgen/xilinx_dsp.pmg | 4 ++-- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index a4602dd63..bd04cc40b 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -49,8 +49,11 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) cell->setPort("\\CLK", st.clock); if (st.ffA) { + SigSpec A = cell->getPort("\\A"); SigSpec D = st.ffA->getPort("\\D"); - cell->setPort("\\A", D.extend_u0(30, true)); + SigSpec Q = st.ffA->getPort("\\Q"); + A.replace(Q, D); + cell->setPort("\\A", A); cell->setParam("\\AREG", State::S1); if (st.ffA->type == "$dff") cell->setPort("\\CEA2", State::S1); @@ -59,8 +62,11 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) else log_abort(); } if (st.ffB) { + SigSpec B = cell->getPort("\\B"); SigSpec D = st.ffB->getPort("\\D"); - cell->setPort("\\B", D.extend_u0(18, true)); + SigSpec Q = st.ffB->getPort("\\Q"); + B.replace(Q, D); + cell->setPort("\\B", B); cell->setParam("\\BREG", State::S1); if (st.ffB->type == "$dff") cell->setPort("\\CEB2", State::S1); @@ -71,7 +77,7 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) if (st.ffP) { SigSpec P = cell->getPort("\\P"); SigSpec Q = st.ffP->getPort("\\Q"); - Q.append(P.extract(GetSize(Q), -1)); + P.replace(Q, P.extract(0, GetSize(Q))); cell->setPort("\\P", Q); cell->setParam("\\PREG", State::S1); if (st.ffP->type == "$dff") diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 4b7bea308..60e972615 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -11,7 +11,7 @@ match ffA select ffA->type.in($dff, $dffe) select param(ffA, \CLK_POLARITY).as_bool() // select nusers(port(ffA, \Q)) == 2 - index port(ffA, \Q).extend_u0(25, true) === port(dsp, \A).extract(0, 25) + index port(ffA, \Q).to_sigbit_pool() === port(dsp, \A).remove_const().to_sigbit_pool() // DSP48E1 does not support clock inversion optional endmatch @@ -25,7 +25,7 @@ match ffB select ffB->type.in($dff, $dffe) select param(ffB, \CLK_POLARITY).as_bool() // select nusers(port(ffB, \Q)) == 2 - index port(ffB, \Q).extend_u0(18, true) === port(dsp, \B) + index port(ffB, \Q).to_sigbit_pool() === port(dsp, \B).remove_const().to_sigbit_pool() optional endmatch -- cgit v1.2.3 From c76607b9bcb2d90fce81ff71e37cc05d21facde4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 18 Jul 2019 08:14:58 -0700 Subject: Wrong wildcard symbol --- passes/pmgen/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/.gitignore b/passes/pmgen/.gitignore index 10e245e00..e52f3282f 100644 --- a/passes/pmgen/.gitignore +++ b/passes/pmgen/.gitignore @@ -1 +1 @@ -/%_pm.h +/*_pm.h -- cgit v1.2.3 From 0727b2c902df37fbbf2fe9acc31d96ce84fa88a7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 18 Jul 2019 13:18:04 -0700 Subject: Fix xilinx_dsp index cast --- passes/pmgen/xilinx_dsp.pmg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 60e972615..51fd733d4 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -11,7 +11,7 @@ match ffA select ffA->type.in($dff, $dffe) select param(ffA, \CLK_POLARITY).as_bool() // select nusers(port(ffA, \Q)) == 2 - index port(ffA, \Q).to_sigbit_pool() === port(dsp, \A).remove_const().to_sigbit_pool() + index > port(ffA, \Q).to_sigbit_pool() === port(dsp, \A).remove_const().to_sigbit_pool() // DSP48E1 does not support clock inversion optional endmatch @@ -25,7 +25,7 @@ match ffB select ffB->type.in($dff, $dffe) select param(ffB, \CLK_POLARITY).as_bool() // select nusers(port(ffB, \Q)) == 2 - index port(ffB, \Q).to_sigbit_pool() === port(dsp, \B).remove_const().to_sigbit_pool() + index > port(ffB, \Q).to_sigbit_pool() === port(dsp, \B).remove_const().to_sigbit_pool() optional endmatch -- cgit v1.2.3 From e075f0dda0999374346ddfc09f83d323f426ddde Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 18 Jul 2019 13:22:22 -0700 Subject: Do not autoremove A/B registers since they might have other consumers --- passes/pmgen/xilinx_dsp.cc | 2 -- 1 file changed, 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index bd04cc40b..0010edf55 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -101,8 +101,6 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) log("\n"); } - pm.autoremove(st.ffA); - pm.autoremove(st.ffB); pm.autoremove(st.ffP); pm.autoremove(st.muxP); pm.blacklist(cell); -- cgit v1.2.3 From 79d63479eab35cf9bbb94b44a42c61e056cd9bcd Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 18 Jul 2019 13:30:35 -0700 Subject: Improve A/B reg packing --- passes/pmgen/xilinx_dsp.cc | 3 +++ passes/pmgen/xilinx_dsp.pmg | 14 ++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 0010edf55..b583988c4 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -23,6 +23,9 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +template bool includes(const T &lhs, const T &rhs) { + return std::includes(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); +} #include "passes/pmgen/xilinx_dsp_pm.h" void pack_xilinx_dsp(xilinx_dsp_pm &pm) diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 51fd733d4..fe907b298 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -9,10 +9,9 @@ endmatch match ffA select ffA->type.in($dff, $dffe) - select param(ffA, \CLK_POLARITY).as_bool() - // select nusers(port(ffA, \Q)) == 2 - index > port(ffA, \Q).to_sigbit_pool() === port(dsp, \A).remove_const().to_sigbit_pool() // DSP48E1 does not support clock inversion + select param(ffA, \CLK_POLARITY).as_bool() + filter includes(port(ffA, \Q).to_sigbit_set(), port(dsp, \A).remove_const().to_sigbit_set()) optional endmatch @@ -23,9 +22,9 @@ endcode match ffB select ffB->type.in($dff, $dffe) + // DSP48E1 does not support clock inversion select param(ffB, \CLK_POLARITY).as_bool() - // select nusers(port(ffB, \Q)) == 2 - index > port(ffB, \Q).to_sigbit_pool() === port(dsp, \B).remove_const().to_sigbit_pool() + filter includes(port(ffB, \Q).to_sigbit_set(), port(dsp, \B).remove_const().to_sigbit_set()) optional endmatch @@ -52,9 +51,10 @@ endcode match ffP select ffP->type.in($dff, $dffe) select nusers(port(ffP, \D)) == 2 + // DSP48E1 does not support clock inversion + select param(ffP, \CLK_POLARITY).as_bool() filter param(ffP, \WIDTH).as_int() == P_WIDTH filter port(ffP, \D) == port(dsp, \P).extract(0, P_WIDTH) - index param(ffP, \CLK_POLARITY) === State::S1 optional endmatch @@ -76,6 +76,8 @@ match ffY if muxP select ffY->type.in($dff, $dffe) select nusers(port(ffY, \D)) == 2 + // DSP48E1 does not support clock inversion + select param(ffY, \CLK_POLARITY).as_bool() index port(ffY, \D) === port(muxP, \Y) endmatch -- cgit v1.2.3 From 08fe63c61e652e51d16bd0259ccff3e482f1aa14 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 18 Jul 2019 14:08:18 -0700 Subject: Improve pattern matcher to match subsets of $dffe? cells --- passes/pmgen/xilinx_dsp.cc | 10 ++++++++-- passes/pmgen/xilinx_dsp.pmg | 24 ++++++++++++++---------- 2 files changed, 22 insertions(+), 12 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index b583988c4..897bc1aaa 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -39,7 +39,8 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) log("dsp: %s\n", log_id(st.dsp, "--")); log("ffP: %s\n", log_id(st.ffP, "--")); log("muxP: %s\n", log_id(st.muxP, "--")); - log("P_WIDTH: %d\n", st.P_WIDTH); + log("P_used: %s\n", log_signal(st.P_used)); + log_module(pm.module); #endif log("Analysing %s.%s for Xilinx DSP register packing.\n", log_id(pm.module), log_id(st.dsp)); @@ -79,8 +80,13 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) } if (st.ffP) { SigSpec P = cell->getPort("\\P"); + SigSpec D; + if (st.muxP) + D = st.muxP->getPort("\\B"); + else + D = st.ffP->getPort("\\D"); SigSpec Q = st.ffP->getPort("\\Q"); - P.replace(Q, P.extract(0, GetSize(Q))); + P.replace(D, Q); cell->setPort("\\P", Q); cell->setParam("\\PREG", State::S1); if (st.ffP->type == "$dff") diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index fe907b298..c2bec4c54 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,7 +1,7 @@ pattern xilinx_dsp state clock -state P_WIDTH +state P_used match dsp select dsp->type.in(\DSP48E1) @@ -39,22 +39,25 @@ code clock } endcode -code P_WIDTH +// Extract the bits of P that actually have a consumer +// (as opposed to being a sign extension) +code P_used SigSpec P = port(dsp, \P); int i; for (i = GetSize(P); i > 0; i--) if (nusers(P[i-1]) > 1) break; - P_WIDTH = i; + P_used = P.extract(0, i).remove_const(); endcode match ffP + if !P_used.empty() select ffP->type.in($dff, $dffe) select nusers(port(ffP, \D)) == 2 // DSP48E1 does not support clock inversion select param(ffP, \CLK_POLARITY).as_bool() - filter param(ffP, \WIDTH).as_int() == P_WIDTH - filter port(ffP, \D) == port(dsp, \P).extract(0, P_WIDTH) + filter param(ffP, \WIDTH).as_int() >= GetSize(P_used) + filter includes(port(ffP, \D).to_sigbit_set(), P_used.to_sigbit_set()) optional endmatch @@ -63,12 +66,12 @@ endmatch // since that would lose information helpful for // efficient wide-mux inference match muxP - if !ffP + if !P_used.empty() && !ffP select muxP->type.in($mux) - select port(muxP, \A).is_fully_undef() - filter param(muxP, \WIDTH).as_int() == P_WIDTH - filter port(muxP, \B) == port(dsp, \P).extract(0, P_WIDTH) select nusers(port(muxP, \B)) == 2 + select port(muxP, \A).is_fully_undef() + filter param(muxP, \WIDTH).as_int() >= GetSize(P_used) + filter includes(port(muxP, \B).to_sigbit_set(), P_used.to_sigbit_set()) optional endmatch @@ -78,7 +81,8 @@ match ffY select nusers(port(ffY, \D)) == 2 // DSP48E1 does not support clock inversion select param(ffY, \CLK_POLARITY).as_bool() - index port(ffY, \D) === port(muxP, \Y) + filter param(ffY, \WIDTH).as_int() >= GetSize(P_used) + filter includes(port(ffY, \D).to_sigbit_set(), port(muxP, \Y).to_sigbit_set()) endmatch code ffP clock -- cgit v1.2.3 From 90ac147eb2139dacc18f80515984ef83d7acb6a1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 18 Jul 2019 15:02:41 -0700 Subject: Do not autoremove ffP aor muxP --- passes/pmgen/xilinx_dsp.cc | 2 -- 1 file changed, 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 897bc1aaa..c71ac5ef8 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -110,8 +110,6 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) log("\n"); } - pm.autoremove(st.ffP); - pm.autoremove(st.muxP); pm.blacklist(cell); } -- cgit v1.2.3 From 802470746c320676d61431d420e33d34c239da84 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 18 Jul 2019 15:22:00 -0700 Subject: Check if RHS is empty first --- passes/pmgen/xilinx_dsp.pmg | 2 ++ 1 file changed, 2 insertions(+) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index c2bec4c54..7a175123e 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -11,6 +11,7 @@ match ffA select ffA->type.in($dff, $dffe) // DSP48E1 does not support clock inversion select param(ffA, \CLK_POLARITY).as_bool() + filter !port(dsp, \A).remove_const().empty() filter includes(port(ffA, \Q).to_sigbit_set(), port(dsp, \A).remove_const().to_sigbit_set()) optional endmatch @@ -24,6 +25,7 @@ match ffB select ffB->type.in($dff, $dffe) // DSP48E1 does not support clock inversion select param(ffB, \CLK_POLARITY).as_bool() + filter !port(dsp, \B).remove_const().empty() filter includes(port(ffB, \Q).to_sigbit_set(), port(dsp, \B).remove_const().to_sigbit_set()) optional endmatch -- cgit v1.2.3 From 09411dd996f75dbce22a6f6979b7d61b0dae24f7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 18 Jul 2019 15:38:28 -0700 Subject: ice40_dsp to accept $__MUL16X16 too --- passes/pmgen/ice40_dsp.pmg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 1f3590d4e..f2b7f2169 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -6,7 +6,7 @@ state sigA sigB sigY sigS state addAB muxAB match mul - select mul->type.in($mul) + select mul->type.in($mul, $__MUL16X16) select GetSize(mul->getPort(\A)) + GetSize(mul->getPort(\B)) > 10 select GetSize(mul->getPort(\Y)) > 10 endmatch -- cgit v1.2.3 From 8f0e796be131c2a47694e786ff901cc9970917c6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 19 Jul 2019 10:38:13 -0700 Subject: Add support for ice40 signed multipliers --- passes/pmgen/ice40_dsp.cc | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 39d033a04..963a7d7a1 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -62,32 +62,27 @@ void create_ice40_dsp(ice40_dsp_pm &pm) return; } - bool mul_signed = st.mul->getParam("\\A_SIGNED").as_bool(); - - if (mul_signed) { - log(" inference of signed iCE40 DSP arithmetic is currently not supported.\n"); - return; - } - - log(" replacing $mul with SB_MAC16 cell.\n"); + log(" replacing %s with SB_MAC16 cell.\n", log_id(st.mul->type)); Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16"); pm.module->swap_names(cell, st.mul); // SB_MAC16 Input Interface + bool a_signed = st.mul->getParam("\\A_SIGNED").as_bool(); + bool b_signed = st.mul->getParam("\\B_SIGNED").as_bool(); SigSpec A = st.sigA; - A.extend_u0(16, mul_signed); + A.extend_u0(16, a_signed); SigSpec B = st.sigB; - B.extend_u0(16, mul_signed); + B.extend_u0(16, b_signed); SigSpec CD; if (st.muxA) CD = st.muxA->getPort("\\B"); if (st.muxB) CD = st.muxB->getPort("\\A"); - CD.extend_u0(32, mul_signed); + CD.extend_u0(32, a_signed && b_signed); cell->setPort("\\A", A); cell->setPort("\\B", B); @@ -198,8 +193,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2)); cell->setParam("\\MODE_8x8", State::S0); - cell->setParam("\\A_SIGNED", mul_signed ? State::S1 : State::S0); - cell->setParam("\\B_SIGNED", mul_signed ? State::S1 : State::S0); + cell->setParam("\\A_SIGNED", a_signed); + cell->setParam("\\B_SIGNED", b_signed); pm.autoremove(st.mul); pm.autoremove(st.ffY); -- cgit v1.2.3 From 9ad11ea2cc25f764bcd4e27dfc12c0f8041cb48a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 19 Jul 2019 10:57:32 -0700 Subject: Fine tune ice40_dsp.pmg, add support for packing subsets of registers --- passes/pmgen/ice40_dsp.cc | 7 ++++-- passes/pmgen/ice40_dsp.pmg | 53 ++++++++++++++++++++++++++------------------- passes/pmgen/xilinx_dsp.cc | 2 +- passes/pmgen/xilinx_dsp.pmg | 20 ++++++++--------- 4 files changed, 47 insertions(+), 35 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 963a7d7a1..f6a701540 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -23,13 +23,16 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +template bool includes(const T &lhs, const T &rhs) { + return std::includes(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); +} #include "passes/pmgen/ice40_dsp_pm.h" void create_ice40_dsp(ice40_dsp_pm &pm) { auto &st = pm.st_ice40_dsp; -#if 0 +#if 1 log("\n"); log("ffA: %s\n", log_id(st.ffA, "--")); log("ffB: %s\n", log_id(st.ffB, "--")); @@ -100,7 +103,7 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setPort("\\IRSTTOP", State::S0); cell->setPort("\\IRSTBOT", State::S0); - if (st.clock_vld) + if (st.clock != SigBit()) { cell->setPort("\\CLK", st.clock); cell->setPort("\\CE", State::S1); diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index f2b7f2169..471b8b519 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -1,8 +1,9 @@ pattern ice40_dsp state clock -state clock_pol clock_vld +state clock_pol state sigA sigB sigY sigS +state sigYused state addAB muxAB match mul @@ -13,68 +14,77 @@ endmatch match ffA select ffA->type.in($dff) - // select nusers(port(ffA, \Q)) == 2 - index port(ffA, \Q) === port(mul, \A) + filter !port(mul, \A).remove_const().empty() + filter includes(port(ffA, \Q).to_sigbit_set(), port(mul, \A).remove_const().to_sigbit_set()) optional endmatch -code sigA clock clock_pol clock_vld +code sigA clock clock_pol sigA = port(mul, \A); if (ffA) { - sigA = port(ffA, \D); + sigA.replace(port(ffA, \Q), port(ffA, \D)); clock = port(ffA, \CLK).as_bit(); clock_pol = param(ffA, \CLK_POLARITY).as_bool(); - clock_vld = true; } endcode match ffB select ffB->type.in($dff) - // select nusers(port(ffB, \Q)) == 2 - index port(ffB, \Q) === port(mul, \B) + filter !port(mul, \B).remove_const().empty() + filter includes(port(ffB, \Q).to_sigbit_set(), port(mul, \B).remove_const().to_sigbit_set()) optional endmatch -code sigB clock clock_pol clock_vld +code sigB clock clock_pol sigB = port(mul, \B); if (ffB) { - sigB = port(ffB, \D); + sigB.replace(port(ffB, \Q), port(ffB, \D)); + SigBit c = port(ffB, \CLK).as_bit(); bool cp = param(ffB, \CLK_POLARITY).as_bool(); - if (clock_vld && (c != clock || cp != clock_pol)) + if (clock != SigBit() && (c != clock || cp != clock_pol)) reject; clock = c; clock_pol = cp; - clock_vld = true; } endcode +// Extract the bits of Y that actually have a consumer +// (as opposed to being a sign extension) +code sigY sigYused + sigY = port(mul, \Y); + int i; + for (i = GetSize(sigY); i > 0; i--) + if (nusers(sigY[i-1]) > 1) + break; + sigYused = sigY.extract(0, i).remove_const(); +endcode + match ffY select ffY->type.in($dff) select nusers(port(ffY, \D)) == 2 - index port(ffY, \D) === port(mul, \Y) + filter param(ffY, \WIDTH).as_int() >= GetSize(sigYused) + filter includes(port(ffY, \D).to_sigbit_set(), sigYused.to_sigbit_set()) optional endmatch -code sigY clock clock_pol clock_vld - sigY = port(mul, \Y); - +code clock clock_pol sigY if (ffY) { - sigY = port(ffY, \Q); + sigY.replace(port(ffY, \D), port(ffY, \Q)); + SigBit c = port(ffY, \CLK).as_bit(); bool cp = param(ffY, \CLK_POLARITY).as_bool(); - if (clock_vld && (c != clock || cp != clock_pol)) + if (clock != SigBit() && (c != clock || cp != clock_pol)) reject; clock = c; clock_pol = cp; - clock_vld = true; } endcode @@ -147,16 +157,15 @@ match ffS index port(ffS, \Q) === sigS endmatch -code clock clock_pol clock_vld +code clock clock_pol if (ffS) { SigBit c = port(ffS, \CLK).as_bit(); bool cp = param(ffS, \CLK_POLARITY).as_bool(); - if (clock_vld && (c != clock || cp != clock_pol)) + if (clock != SigBit() && (c != clock || cp != clock_pol)) reject; clock = c; clock_pol = cp; - clock_vld = true; } endcode diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index c71ac5ef8..d87d63670 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -39,7 +39,7 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) log("dsp: %s\n", log_id(st.dsp, "--")); log("ffP: %s\n", log_id(st.ffP, "--")); log("muxP: %s\n", log_id(st.muxP, "--")); - log("P_used: %s\n", log_signal(st.P_used)); + log("sigPused: %s\n", log_signal(st.sigPused)); log_module(pm.module); #endif diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 7a175123e..a97ab4dd5 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,7 +1,7 @@ pattern xilinx_dsp state clock -state P_used +state sigPused match dsp select dsp->type.in(\DSP48E1) @@ -43,23 +43,23 @@ endcode // Extract the bits of P that actually have a consumer // (as opposed to being a sign extension) -code P_used +code sigPused SigSpec P = port(dsp, \P); int i; for (i = GetSize(P); i > 0; i--) if (nusers(P[i-1]) > 1) break; - P_used = P.extract(0, i).remove_const(); + sigPused = P.extract(0, i).remove_const(); endcode match ffP - if !P_used.empty() + if !sigPused.empty() select ffP->type.in($dff, $dffe) select nusers(port(ffP, \D)) == 2 // DSP48E1 does not support clock inversion select param(ffP, \CLK_POLARITY).as_bool() - filter param(ffP, \WIDTH).as_int() >= GetSize(P_used) - filter includes(port(ffP, \D).to_sigbit_set(), P_used.to_sigbit_set()) + filter param(ffP, \WIDTH).as_int() >= GetSize(sigPused) + filter includes(port(ffP, \D).to_sigbit_set(), sigPused.to_sigbit_set()) optional endmatch @@ -68,12 +68,12 @@ endmatch // since that would lose information helpful for // efficient wide-mux inference match muxP - if !P_used.empty() && !ffP + if !sigPused.empty() && !ffP select muxP->type.in($mux) select nusers(port(muxP, \B)) == 2 select port(muxP, \A).is_fully_undef() - filter param(muxP, \WIDTH).as_int() >= GetSize(P_used) - filter includes(port(muxP, \B).to_sigbit_set(), P_used.to_sigbit_set()) + filter param(muxP, \WIDTH).as_int() >= GetSize(sigPused) + filter includes(port(muxP, \B).to_sigbit_set(), sigPused.to_sigbit_set()) optional endmatch @@ -83,7 +83,7 @@ match ffY select nusers(port(ffY, \D)) == 2 // DSP48E1 does not support clock inversion select param(ffY, \CLK_POLARITY).as_bool() - filter param(ffY, \WIDTH).as_int() >= GetSize(P_used) + filter param(ffY, \WIDTH).as_int() >= GetSize(sigPused) filter includes(port(ffY, \D).to_sigbit_set(), port(muxP, \Y).to_sigbit_set()) endmatch -- cgit v1.2.3 From f9d08a5e5e0ce637b510f6c19a4cd72edf17b3f7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 19 Jul 2019 20:25:28 -0700 Subject: Cleanup --- passes/pmgen/ice40_dsp.pmg | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 471b8b519..fb5fe0951 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -23,10 +23,10 @@ code sigA clock clock_pol sigA = port(mul, \A); if (ffA) { - sigA.replace(port(ffA, \Q), port(ffA, \D)); - clock = port(ffA, \CLK).as_bit(); clock_pol = param(ffA, \CLK_POLARITY).as_bool(); + + sigA.replace(port(ffA, \Q), port(ffA, \D)); } endcode @@ -41,8 +41,6 @@ code sigB clock clock_pol sigB = port(mul, \B); if (ffB) { - sigB.replace(port(ffB, \Q), port(ffB, \D)); - SigBit c = port(ffB, \CLK).as_bit(); bool cp = param(ffB, \CLK_POLARITY).as_bool(); @@ -51,6 +49,8 @@ code sigB clock clock_pol clock = c; clock_pol = cp; + + sigB.replace(port(ffB, \Q), port(ffB, \D)); } endcode @@ -62,7 +62,7 @@ code sigY sigYused for (i = GetSize(sigY); i > 0; i--) if (nusers(sigY[i-1]) > 1) break; - sigYused = sigY.extract(0, i).remove_const(); + sigYused = sigY.extract(0, i); endcode match ffY -- cgit v1.2.3 From e0720a8018702a2b4de108363a51c8bffc287b55 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 19 Jul 2019 22:47:08 -0700 Subject: Restore old ffY behaviour --- passes/pmgen/ice40_dsp.pmg | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index fb5fe0951..e4c6238c5 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -3,7 +3,6 @@ pattern ice40_dsp state clock state clock_pol state sigA sigB sigY sigS -state sigYused state addAB muxAB match mul @@ -54,28 +53,18 @@ code sigB clock clock_pol } endcode -// Extract the bits of Y that actually have a consumer -// (as opposed to being a sign extension) -code sigY sigYused - sigY = port(mul, \Y); - int i; - for (i = GetSize(sigY); i > 0; i--) - if (nusers(sigY[i-1]) > 1) - break; - sigYused = sigY.extract(0, i); -endcode - match ffY select ffY->type.in($dff) select nusers(port(ffY, \D)) == 2 - filter param(ffY, \WIDTH).as_int() >= GetSize(sigYused) - filter includes(port(ffY, \D).to_sigbit_set(), sigYused.to_sigbit_set()) + index port(ffY, \D) === port(mul, \Y) optional endmatch -code clock clock_pol sigY +code sigY clock clock_pol + sigY = port(mul, \Y); + if (ffY) { - sigY.replace(port(ffY, \D), port(ffY, \Q)); + sigY = port(ffY, \Q); SigBit c = port(ffY, \CLK).as_bit(); bool cp = param(ffY, \CLK_POLARITY).as_bool(); -- cgit v1.2.3 From 5a14b6e1f6331d7587d566173e0d82e0c6c77f4c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 22 Jul 2019 13:01:49 -0700 Subject: Pack adders not just accumulators --- passes/pmgen/ice40_dsp.cc | 38 ++++++++++++++++++++++++++------------ passes/pmgen/ice40_dsp.pmg | 11 +++++++---- 2 files changed, 33 insertions(+), 16 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index f6a701540..7215ed473 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -80,17 +80,25 @@ void create_ice40_dsp(ice40_dsp_pm &pm) SigSpec B = st.sigB; B.extend_u0(16, b_signed); + // MAC only if ffS exists and adder's other input (sigS) + // is output of ffS + bool accum = (st.ffS && st.sigS == st.ffS->getPort("\\Q")); + SigSpec CD; - if (st.muxA) - CD = st.muxA->getPort("\\B"); - if (st.muxB) - CD = st.muxB->getPort("\\A"); + if (st.ffS) { + if (st.muxA) + CD = st.muxA->getPort("\\B"); + else if (st.muxB) + CD = st.muxB->getPort("\\A"); + } + else if (!accum) + CD = st.sigS.extend_u0(32, st.sigS_signed); CD.extend_u0(32, a_signed && b_signed); cell->setPort("\\A", A); cell->setPort("\\B", B); - cell->setPort("\\C", CD.extract(0, 16)); - cell->setPort("\\D", CD.extract(16, 16)); + cell->setPort("\\C", CD.extract(16, 16)); + cell->setPort("\\D", CD.extract(0, 16)); cell->setParam("\\A_REG", st.ffA ? State::S1 : State::S0); cell->setParam("\\B_REG", st.ffB ? State::S1 : State::S0); @@ -145,14 +153,19 @@ void create_ice40_dsp(ice40_dsp_pm &pm) // SB_MAC16 Output Interface - SigSpec O = st.ffS ? st.sigS : st.sigY; + if (st.addAB) log_cell(st.addAB); + SigSpec O = st.ffS ? st.sigS : (st.addAB ? st.addAB->getPort("\\Y") : st.sigY); if (GetSize(O) < 32) O.append(pm.module->addWire(NEW_ID, 32-GetSize(O))); cell->setPort("\\O", O); if (st.addAB) { - log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); + log_warning("sigS = %s\n", log_signal(st.sigS)); + if (accum) + log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); + else + log(" adder %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); cell->setPort("\\ADDSUBTOP", st.addAB->type == "$add" ? State::S0 : State::S1); cell->setPort("\\ADDSUBBOT", st.addAB->type == "$add" ? State::S0 : State::S1); } else { @@ -185,14 +198,14 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam("\\PIPELINE_16x16_MULT_REG1", st.ffY ? State::S1 : State::S0); cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0); - cell->setParam("\\TOPOUTPUT_SELECT", Const(st.ffS ? 1 : 3, 2)); + cell->setParam("\\TOPOUTPUT_SELECT", Const(st.ffS ? 1 : (st.addAB ? 0 : 3), 2)); cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2)); - cell->setParam("\\TOPADDSUB_UPPERINPUT", State::S0); + cell->setParam("\\TOPADDSUB_UPPERINPUT", st.ffS ? State::S0 : State::S1); cell->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2)); - cell->setParam("\\BOTOUTPUT_SELECT", Const(st.ffS ? 1 : 3, 2)); + cell->setParam("\\BOTOUTPUT_SELECT", Const(st.ffS ? 1 : (st.addAB ? 0 : 3), 2)); cell->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2)); - cell->setParam("\\BOTADDSUB_UPPERINPUT", State::S0); + cell->setParam("\\BOTADDSUB_UPPERINPUT", st.ffS ? State::S0 : State::S1); cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2)); cell->setParam("\\MODE_8x8", State::S0); @@ -201,6 +214,7 @@ void create_ice40_dsp(ice40_dsp_pm &pm) pm.autoremove(st.mul); pm.autoremove(st.ffY); + pm.autoremove(st.addAB); pm.autoremove(st.ffS); } diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index e4c6238c5..a92cf8dd4 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -1,7 +1,7 @@ pattern ice40_dsp state clock -state clock_pol +state clock_pol sigS_signed state sigA sigB sigY sigS state addAB muxAB @@ -92,14 +92,16 @@ match addB optional endmatch -code addAB sigS +code addAB sigS sigS_signed if (addA) { addAB = addA; - sigS = port(addA, \B); + sigS = port(addAB, \B); + sigS_signed = param(addAB, \B_SIGNED).as_bool(); } if (addB) { addAB = addB; - sigS = port(addB, \A); + sigS = port(addAB, \A); + sigS_signed = param(addAB, \A_SIGNED).as_bool(); } if (addAB) { int natural_mul_width = GetSize(sigA) + GetSize(sigB); @@ -144,6 +146,7 @@ match ffS select nusers(port(ffS, \D)) == 2 index port(ffS, \D) === port(muxAB, \Y) index port(ffS, \Q) === sigS + optional endmatch code clock clock_pol -- cgit v1.2.3 From 304cefbbe2b0c000c30e8d73d1761488be65ccf0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 22 Jul 2019 15:05:16 -0700 Subject: Pack Y register --- passes/pmgen/ice40_dsp.cc | 48 +++++++++++++++++++++++++++++----------------- passes/pmgen/ice40_dsp.pmg | 12 ++++++++---- 2 files changed, 38 insertions(+), 22 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 7215ed473..5f6a20dfc 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -80,20 +80,25 @@ void create_ice40_dsp(ice40_dsp_pm &pm) SigSpec B = st.sigB; B.extend_u0(16, b_signed); - // MAC only if ffS exists and adder's other input (sigS) - // is output of ffS - bool accum = (st.ffS && st.sigS == st.ffS->getPort("\\Q")); - SigSpec CD; - if (st.ffS) { - if (st.muxA) - CD = st.muxA->getPort("\\B"); - else if (st.muxB) - CD = st.muxB->getPort("\\A"); - } - else if (!accum) - CD = st.sigS.extend_u0(32, st.sigS_signed); - CD.extend_u0(32, a_signed && b_signed); + bool CD_signed = false; + if (st.muxAB != st.addAB) { + if (st.muxA) + CD = st.muxA->getPort("\\B"); + else if (st.muxB) + CD = st.muxB->getPort("\\A"); + else log_abort(); + CD_signed = a_signed && b_signed; // TODO: Do muxes have [AB]_SIGNED? + } + else if (st.addAB) { + if (st.addA) + CD = st.addAB->getPort("\\B"); + else if (st.addB) + CD = st.addAB->getPort("\\A"); + else log_abort(); + CD_signed = st.sigS_signed; + } + CD.extend_u0(32, CD_signed); cell->setPort("\\A", A); cell->setPort("\\B", B); @@ -153,15 +158,21 @@ void create_ice40_dsp(ice40_dsp_pm &pm) // SB_MAC16 Output Interface - if (st.addAB) log_cell(st.addAB); SigSpec O = st.ffS ? st.sigS : (st.addAB ? st.addAB->getPort("\\Y") : st.sigY); if (GetSize(O) < 32) O.append(pm.module->addWire(NEW_ID, 32-GetSize(O))); cell->setPort("\\O", O); + // MAC only if ffS exists and adder's other input (sigS) + // is output of ffS + bool accum = false; if (st.addAB) { - log_warning("sigS = %s\n", log_signal(st.sigS)); + if (st.addA) + accum = (st.ffS && st.addAB->getPort("\\B") == st.ffS->getPort("\\Q")); + else if (st.addB) + accum = (st.ffS && st.addAB->getPort("\\A") == st.ffS->getPort("\\Q")); + else log_abort(); if (accum) log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); else @@ -200,12 +211,12 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam("\\TOPOUTPUT_SELECT", Const(st.ffS ? 1 : (st.addAB ? 0 : 3), 2)); cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2)); - cell->setParam("\\TOPADDSUB_UPPERINPUT", st.ffS ? State::S0 : State::S1); + cell->setParam("\\TOPADDSUB_UPPERINPUT", accum ? State::S0 : State::S1); cell->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2)); cell->setParam("\\BOTOUTPUT_SELECT", Const(st.ffS ? 1 : (st.addAB ? 0 : 3), 2)); cell->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2)); - cell->setParam("\\BOTADDSUB_UPPERINPUT", st.ffS ? State::S0 : State::S1); + cell->setParam("\\BOTADDSUB_UPPERINPUT", accum ? State::S0 : State::S1); cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2)); cell->setParam("\\MODE_8x8", State::S0); @@ -215,7 +226,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm) pm.autoremove(st.mul); pm.autoremove(st.ffY); pm.autoremove(st.addAB); - pm.autoremove(st.ffS); + if (st.ffS) + st.ffS->connections_.at("\\Q").replace(st.sigS, pm.module->addWire(NEW_ID, GetSize(st.sigS))); } struct Ice40DspPass : public Pass { diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index a92cf8dd4..223f9b2e4 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -143,17 +143,21 @@ endcode match ffS if muxAB select ffS->type.in($dff) - select nusers(port(ffS, \D)) == 2 - index port(ffS, \D) === port(muxAB, \Y) - index port(ffS, \Q) === sigS + filter nusers(port(muxAB, \Y)) == 2 + filter includes(port(ffS, \D).to_sigbit_set(), port(muxAB, \Y).to_sigbit_set()) optional endmatch -code clock clock_pol +code clock clock_pol sigS if (ffS) { SigBit c = port(ffS, \CLK).as_bit(); bool cp = param(ffS, \CLK_POLARITY).as_bool(); + if (port(ffS, \Q) != sigS) { + sigS = port(muxAB, \Y); + sigS.replace(port(ffS, \D), port(ffS, \Q)); + } + if (clock != SigBit() && (c != clock || cp != clock_pol)) reject; -- cgit v1.2.3 From 4d71ab384d640f53435d2e4773b2277f385cda27 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 22 Jul 2019 15:08:26 -0700 Subject: Rename according to vendor doc TN1295 --- passes/pmgen/ice40_dsp.cc | 48 +++++++++++++++++------------------ passes/pmgen/ice40_dsp.pmg | 62 +++++++++++++++++++++++----------------------- 2 files changed, 55 insertions(+), 55 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 5f6a20dfc..d4e2914d9 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -37,10 +37,10 @@ void create_ice40_dsp(ice40_dsp_pm &pm) log("ffA: %s\n", log_id(st.ffA, "--")); log("ffB: %s\n", log_id(st.ffB, "--")); log("mul: %s\n", log_id(st.mul, "--")); - log("ffY: %s\n", log_id(st.ffY, "--")); + log("ffH: %s\n", log_id(st.ffH, "--")); log("addAB: %s\n", log_id(st.addAB, "--")); log("muxAB: %s\n", log_id(st.muxAB, "--")); - log("ffS: %s\n", log_id(st.ffS, "--")); + log("ffO: %s\n", log_id(st.ffO, "--")); #endif log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(st.mul)); @@ -55,13 +55,13 @@ void create_ice40_dsp(ice40_dsp_pm &pm) return; } - if (GetSize(st.sigS) > 32) { - log(" accumulator (%s) is too large (%d > 32).\n", log_signal(st.sigS), GetSize(st.sigS)); + if (GetSize(st.sigO) > 32) { + log(" accumulator (%s) is too large (%d > 32).\n", log_signal(st.sigO), GetSize(st.sigO)); return; } - if (GetSize(st.sigY) > 32) { - log(" output (%s) is too large (%d > 32).\n", log_signal(st.sigY), GetSize(st.sigY)); + if (GetSize(st.sigH) > 32) { + log(" output (%s) is too large (%d > 32).\n", log_signal(st.sigH), GetSize(st.sigH)); return; } @@ -96,7 +96,7 @@ void create_ice40_dsp(ice40_dsp_pm &pm) else if (st.addB) CD = st.addAB->getPort("\\A"); else log_abort(); - CD_signed = st.sigS_signed; + CD_signed = st.sigO_signed; } CD.extend_u0(32, CD_signed); @@ -130,11 +130,11 @@ void create_ice40_dsp(ice40_dsp_pm &pm) if (st.ffB) log(" ffB:%s", log_id(st.ffB)); - if (st.ffY) - log(" ffY:%s", log_id(st.ffY)); + if (st.ffH) + log(" ffH:%s", log_id(st.ffH)); - if (st.ffS) - log(" ffS:%s", log_id(st.ffS)); + if (st.ffO) + log(" ffO:%s", log_id(st.ffO)); log("\n"); } @@ -158,20 +158,20 @@ void create_ice40_dsp(ice40_dsp_pm &pm) // SB_MAC16 Output Interface - SigSpec O = st.ffS ? st.sigS : (st.addAB ? st.addAB->getPort("\\Y") : st.sigY); + SigSpec O = st.ffO ? st.sigO : (st.addAB ? st.addAB->getPort("\\Y") : st.sigH); if (GetSize(O) < 32) O.append(pm.module->addWire(NEW_ID, 32-GetSize(O))); cell->setPort("\\O", O); - // MAC only if ffS exists and adder's other input (sigS) - // is output of ffS + // MAC only if ffO exists and adder's other input (sigO) + // is output of ffO bool accum = false; if (st.addAB) { if (st.addA) - accum = (st.ffS && st.addAB->getPort("\\B") == st.ffS->getPort("\\Q")); + accum = (st.ffO && st.addAB->getPort("\\B") == st.ffO->getPort("\\Q")); else if (st.addB) - accum = (st.ffS && st.addAB->getPort("\\A") == st.ffS->getPort("\\Q")); + accum = (st.ffO && st.addAB->getPort("\\A") == st.ffO->getPort("\\Q")); else log_abort(); if (accum) log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); @@ -204,17 +204,17 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam("\\C_REG", State::S0); cell->setParam("\\D_REG", State::S0); - cell->setParam("\\TOP_8x8_MULT_REG", st.ffY ? State::S1 : State::S0); - cell->setParam("\\BOT_8x8_MULT_REG", st.ffY ? State::S1 : State::S0); - cell->setParam("\\PIPELINE_16x16_MULT_REG1", st.ffY ? State::S1 : State::S0); + cell->setParam("\\TOP_8x8_MULT_REG", st.ffH ? State::S1 : State::S0); + cell->setParam("\\BOT_8x8_MULT_REG", st.ffH ? State::S1 : State::S0); + cell->setParam("\\PIPELINE_16x16_MULT_REG1", st.ffH ? State::S1 : State::S0); cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0); - cell->setParam("\\TOPOUTPUT_SELECT", Const(st.ffS ? 1 : (st.addAB ? 0 : 3), 2)); + cell->setParam("\\TOPOUTPUT_SELECT", Const(st.ffO ? 1 : (st.addAB ? 0 : 3), 2)); cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2)); cell->setParam("\\TOPADDSUB_UPPERINPUT", accum ? State::S0 : State::S1); cell->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2)); - cell->setParam("\\BOTOUTPUT_SELECT", Const(st.ffS ? 1 : (st.addAB ? 0 : 3), 2)); + cell->setParam("\\BOTOUTPUT_SELECT", Const(st.ffO ? 1 : (st.addAB ? 0 : 3), 2)); cell->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2)); cell->setParam("\\BOTADDSUB_UPPERINPUT", accum ? State::S0 : State::S1); cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2)); @@ -224,10 +224,10 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam("\\B_SIGNED", b_signed); pm.autoremove(st.mul); - pm.autoremove(st.ffY); + pm.autoremove(st.ffH); pm.autoremove(st.addAB); - if (st.ffS) - st.ffS->connections_.at("\\Q").replace(st.sigS, pm.module->addWire(NEW_ID, GetSize(st.sigS))); + if (st.ffO) + st.ffO->connections_.at("\\Q").replace(st.sigO, pm.module->addWire(NEW_ID, GetSize(st.sigO))); } struct Ice40DspPass : public Pass { diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 223f9b2e4..a74bd7902 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -1,8 +1,8 @@ pattern ice40_dsp state clock -state clock_pol sigS_signed -state sigA sigB sigY sigS +state clock_pol sigO_signed +state sigA sigB sigH sigO state addAB muxAB match mul @@ -53,21 +53,21 @@ code sigB clock clock_pol } endcode -match ffY - select ffY->type.in($dff) - select nusers(port(ffY, \D)) == 2 - index port(ffY, \D) === port(mul, \Y) +match ffH + select ffH->type.in($dff) + select nusers(port(ffH, \D)) == 2 + index port(ffH, \D) === port(mul, \Y) optional endmatch -code sigY clock clock_pol - sigY = port(mul, \Y); +code sigH clock clock_pol + sigH = port(mul, \Y); - if (ffY) { - sigY = port(ffY, \Q); + if (ffH) { + sigH = port(ffH, \Q); - SigBit c = port(ffY, \CLK).as_bit(); - bool cp = param(ffY, \CLK_POLARITY).as_bool(); + SigBit c = port(ffH, \CLK).as_bit(); + bool cp = param(ffH, \CLK_POLARITY).as_bool(); if (clock != SigBit() && (c != clock || cp != clock_pol)) reject; @@ -80,7 +80,7 @@ endcode match addA select addA->type.in($add) select nusers(port(addA, \A)) == 2 - index port(addA, \A) === sigY + index port(addA, \A) === sigH optional endmatch @@ -88,25 +88,25 @@ match addB if !addA select addB->type.in($add, $sub) select nusers(port(addB, \B)) == 2 - index port(addB, \B) === sigY + index port(addB, \B) === sigH optional endmatch -code addAB sigS sigS_signed +code addAB sigO sigO_signed if (addA) { addAB = addA; - sigS = port(addAB, \B); - sigS_signed = param(addAB, \B_SIGNED).as_bool(); + sigO = port(addAB, \B); + sigO_signed = param(addAB, \B_SIGNED).as_bool(); } if (addB) { addAB = addB; - sigS = port(addAB, \A); - sigS_signed = param(addAB, \A_SIGNED).as_bool(); + sigO = port(addAB, \A); + sigO_signed = param(addAB, \A_SIGNED).as_bool(); } if (addAB) { int natural_mul_width = GetSize(sigA) + GetSize(sigB); - int actual_mul_width = GetSize(sigY); - int actual_acc_width = GetSize(sigS); + int actual_mul_width = GetSize(sigH); + int actual_acc_width = GetSize(sigO); if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width)) reject; @@ -140,22 +140,22 @@ code muxAB muxAB = muxB; endcode -match ffS +match ffO if muxAB - select ffS->type.in($dff) + select ffO->type.in($dff) filter nusers(port(muxAB, \Y)) == 2 - filter includes(port(ffS, \D).to_sigbit_set(), port(muxAB, \Y).to_sigbit_set()) + filter includes(port(ffO, \D).to_sigbit_set(), port(muxAB, \Y).to_sigbit_set()) optional endmatch -code clock clock_pol sigS - if (ffS) { - SigBit c = port(ffS, \CLK).as_bit(); - bool cp = param(ffS, \CLK_POLARITY).as_bool(); +code clock clock_pol sigO + if (ffO) { + SigBit c = port(ffO, \CLK).as_bit(); + bool cp = param(ffO, \CLK_POLARITY).as_bool(); - if (port(ffS, \Q) != sigS) { - sigS = port(muxAB, \Y); - sigS.replace(port(ffS, \D), port(ffS, \Q)); + if (port(ffO, \Q) != sigO) { + sigO = port(muxAB, \Y); + sigO.replace(port(ffO, \D), port(ffO, \Q)); } if (clock != SigBit() && (c != clock || cp != clock_pol)) -- cgit v1.2.3 From 068617f0948b411fcf9cdf047c6dfc600a0689bb Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 22 Jul 2019 16:12:57 -0700 Subject: Pack hi and lo registers separately --- passes/pmgen/ice40_dsp.cc | 47 ++++++++++++++++++++--------------- passes/pmgen/ice40_dsp.pmg | 62 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 70 insertions(+), 39 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index d4e2914d9..6b6fd5640 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -34,13 +34,14 @@ void create_ice40_dsp(ice40_dsp_pm &pm) #if 1 log("\n"); - log("ffA: %s\n", log_id(st.ffA, "--")); - log("ffB: %s\n", log_id(st.ffB, "--")); - log("mul: %s\n", log_id(st.mul, "--")); - log("ffH: %s\n", log_id(st.ffH, "--")); - log("addAB: %s\n", log_id(st.addAB, "--")); - log("muxAB: %s\n", log_id(st.muxAB, "--")); - log("ffO: %s\n", log_id(st.ffO, "--")); + log("ffA: %s\n", log_id(st.ffA, "--")); + log("ffB: %s\n", log_id(st.ffB, "--")); + log("mul: %s\n", log_id(st.mul, "--")); + log("ffH: %s\n", log_id(st.ffH, "--")); + log("addAB: %s\n", log_id(st.addAB, "--")); + log("muxAB: %s\n", log_id(st.muxAB, "--")); + log("ffO_lo: %s\n", log_id(st.ffO_lo, "--")); + log("ffO_hi: %s\n", log_id(st.ffO_hi, "--")); #endif log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(st.mul)); @@ -133,8 +134,10 @@ void create_ice40_dsp(ice40_dsp_pm &pm) if (st.ffH) log(" ffH:%s", log_id(st.ffH)); - if (st.ffO) - log(" ffO:%s", log_id(st.ffO)); + if (st.ffO_lo) + log(" ffO_lo:%s", log_id(st.ffO_lo)); + if (st.ffO_hi) + log(" ffO_hi:%s", log_id(st.ffO_hi)); log("\n"); } @@ -158,20 +161,22 @@ void create_ice40_dsp(ice40_dsp_pm &pm) // SB_MAC16 Output Interface - SigSpec O = st.ffO ? st.sigO : (st.addAB ? st.addAB->getPort("\\Y") : st.sigH); - if (GetSize(O) < 32) - O.append(pm.module->addWire(NEW_ID, 32-GetSize(O))); + SigSpec O_lo = (st.ffO_lo ? st.sigO : (st.addAB ? st.addAB->getPort("\\Y") : st.sigH)).extract(0,16); + if (GetSize(O_lo) < 16) + O_lo.append(pm.module->addWire(NEW_ID, 16-GetSize(O_lo))); + SigSpec O_hi = (st.ffO_hi ? st.sigO : (st.addAB ? st.addAB->getPort("\\Y") : st.sigH)).extract(16,16); + if (GetSize(O_hi) < 16) + O_hi.append(pm.module->addWire(NEW_ID, 16-GetSize(O_hi))); + SigSpec O{O_hi,O_lo}; cell->setPort("\\O", O); - // MAC only if ffO exists and adder's other input (sigO) - // is output of ffO bool accum = false; if (st.addAB) { if (st.addA) - accum = (st.ffO && st.addAB->getPort("\\B") == st.ffO->getPort("\\Q")); + accum = (st.ffO_lo && st.ffO_hi && st.addAB->getPort("\\B") == O); else if (st.addB) - accum = (st.ffO && st.addAB->getPort("\\A") == st.ffO->getPort("\\Q")); + accum = (st.ffO_lo && st.ffO_hi && st.addAB->getPort("\\A") == O); else log_abort(); if (accum) log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); @@ -209,12 +214,12 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam("\\PIPELINE_16x16_MULT_REG1", st.ffH ? State::S1 : State::S0); cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0); - cell->setParam("\\TOPOUTPUT_SELECT", Const(st.ffO ? 1 : (st.addAB ? 0 : 3), 2)); + cell->setParam("\\TOPOUTPUT_SELECT", Const(st.ffO_hi ? 1 : (st.addAB ? 0 : 3), 2)); cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2)); cell->setParam("\\TOPADDSUB_UPPERINPUT", accum ? State::S0 : State::S1); cell->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2)); - cell->setParam("\\BOTOUTPUT_SELECT", Const(st.ffO ? 1 : (st.addAB ? 0 : 3), 2)); + cell->setParam("\\BOTOUTPUT_SELECT", Const(st.ffO_lo ? 1 : (st.addAB ? 0 : 3), 2)); cell->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2)); cell->setParam("\\BOTADDSUB_UPPERINPUT", accum ? State::S0 : State::S1); cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2)); @@ -226,8 +231,10 @@ void create_ice40_dsp(ice40_dsp_pm &pm) pm.autoremove(st.mul); pm.autoremove(st.ffH); pm.autoremove(st.addAB); - if (st.ffO) - st.ffO->connections_.at("\\Q").replace(st.sigO, pm.module->addWire(NEW_ID, GetSize(st.sigO))); + if (st.ffO_lo) + st.ffO_lo->connections_.at("\\Q").replace(O.extract(0,16), pm.module->addWire(NEW_ID, 16)); + if (st.ffO_hi) + st.ffO_hi->connections_.at("\\Q").replace(O.extract(16,16), pm.module->addWire(NEW_ID, 16)); } struct Ice40DspPass : public Pass { diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index a74bd7902..0684edc1b 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -60,11 +60,13 @@ match ffH optional endmatch -code sigH clock clock_pol +code sigH sigO clock clock_pol sigH = port(mul, \Y); + sigO = sigH; if (ffH) { sigH = port(ffH, \Q); + sigO = sigH; SigBit c = port(ffH, \CLK).as_bit(); bool cp = param(ffH, \CLK_POLARITY).as_bool(); @@ -95,12 +97,10 @@ endmatch code addAB sigO sigO_signed if (addA) { addAB = addA; - sigO = port(addAB, \B); sigO_signed = param(addAB, \B_SIGNED).as_bool(); } if (addB) { addAB = addB; - sigO = port(addAB, \A); sigO_signed = param(addAB, \A_SIGNED).as_bool(); } if (addAB) { @@ -112,6 +112,8 @@ code addAB sigO sigO_signed reject; if ((actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(addAB, \A_SIGNED).as_bool())) reject; + + sigO = port(addAB, \Y); } endcode @@ -132,36 +134,58 @@ match muxB optional endmatch -code muxAB +code muxAB sigO muxAB = addAB; if (muxA) muxAB = muxA; if (muxB) muxAB = muxB; + if (muxA || muxB) + sigO = port(muxAB, \Y); endcode -match ffO - if muxAB - select ffO->type.in($dff) - filter nusers(port(muxAB, \Y)) == 2 - filter includes(port(ffO, \D).to_sigbit_set(), port(muxAB, \Y).to_sigbit_set()) +match ffO_lo + select ffO_lo->type.in($dff) + filter nusers(sigO.extract(0,16)) == 2 + filter includes(port(ffO_lo, \D).to_sigbit_set(), sigO.extract(0,16).to_sigbit_set()) + optional +endmatch + +match ffO_hi + select ffO_hi->type.in($dff) + filter nusers(sigO.extract(16,16)) == 2 + filter includes(port(ffO_hi, \D).to_sigbit_set(), sigO.extract(16,16).to_sigbit_set()) optional endmatch code clock clock_pol sigO - if (ffO) { - SigBit c = port(ffO, \CLK).as_bit(); - bool cp = param(ffO, \CLK_POLARITY).as_bool(); + if (ffO_lo || ffO_hi) { + if (ffO_lo) { + SigBit c = port(ffO_lo, \CLK).as_bit(); + bool cp = param(ffO_lo, \CLK_POLARITY).as_bool(); - if (port(ffO, \Q) != sigO) { - sigO = port(muxAB, \Y); - sigO.replace(port(ffO, \D), port(ffO, \Q)); + if (clock != SigBit() && (c != clock || cp != clock_pol)) + reject; + + clock = c; + clock_pol = cp; + + if (port(ffO_lo, \Q) != sigO.extract(0,16)) + sigO.replace(port(ffO_lo, \D), port(ffO_lo, \Q)); } - if (clock != SigBit() && (c != clock || cp != clock_pol)) - reject; + if (ffO_hi) { + SigBit c = port(ffO_hi, \CLK).as_bit(); + bool cp = param(ffO_hi, \CLK_POLARITY).as_bool(); - clock = c; - clock_pol = cp; + if (clock != SigBit() && (c != clock || cp != clock_pol)) + reject; + + clock = c; + clock_pol = cp; + + if (port(ffO_hi, \Q) != sigO.extract(16,16)) + sigO.replace(port(ffO_hi, \D), port(ffO_hi, \Q)); + } } endcode -- cgit v1.2.3 From 33c984a0445b2bb24081adf324b2254c454266d1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 22 Jul 2019 16:37:13 -0700 Subject: Fix spacing --- passes/pmgen/ice40_dsp.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 6b6fd5640..f365ae8b6 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -174,9 +174,9 @@ void create_ice40_dsp(ice40_dsp_pm &pm) bool accum = false; if (st.addAB) { if (st.addA) - accum = (st.ffO_lo && st.ffO_hi && st.addAB->getPort("\\B") == O); + accum = (st.ffO_lo && st.ffO_hi && st.addAB->getPort("\\B") == O); else if (st.addB) - accum = (st.ffO_lo && st.ffO_hi && st.addAB->getPort("\\A") == O); + accum = (st.ffO_lo && st.ffO_hi && st.addAB->getPort("\\A") == O); else log_abort(); if (accum) log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); -- cgit v1.2.3 From 4f11ff8ebd23d1f74aae6296ff0a4f792ac97749 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 23 Jul 2019 13:58:56 -0700 Subject: Fix typo --- passes/pmgen/ice40_dsp.pmg | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 0684edc1b..73ece6962 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -1,8 +1,8 @@ pattern ice40_dsp state clock -state clock_pol sigO_signed -state sigA sigB sigH sigO +state clock_pol sigCD_signed +state sigA sigB sigCD sigH sigO state addAB muxAB match mul @@ -94,14 +94,16 @@ match addB optional endmatch -code addAB sigO sigO_signed +code addAB sigCD sigCD_signed sigO if (addA) { addAB = addA; - sigO_signed = param(addAB, \B_SIGNED).as_bool(); + sigCD = port(addAB, \B); + sigCD_signed = param(addAB, \B_SIGNED).as_bool(); } if (addB) { addAB = addB; - sigO_signed = param(addAB, \A_SIGNED).as_bool(); + sigCD = port(addAB, \A); + sigCD_signed = param(addAB, \A_SIGNED).as_bool(); } if (addAB) { int natural_mul_width = GetSize(sigA) + GetSize(sigB); @@ -118,30 +120,36 @@ code addAB sigO sigO_signed endcode match muxA - if addAB + if sigCD.empty() select muxA->type.in($mux) select nusers(port(muxA, \A)) == 2 - index port(muxA, \A) === port(addAB, \Y) + index port(muxA, \A) === sigO optional endmatch match muxB - if addAB + if sigCD.empty() if !muxA select muxB->type.in($mux) select nusers(port(muxB, \B)) == 2 - index port(muxB, \B) === port(addAB, \Y) + index port(muxB, \B) === sigO optional endmatch -code muxAB sigO +code muxAB sigCD sigCD_signed sigO muxAB = addAB; - if (muxA) + if (muxA) { muxAB = muxA; - if (muxB) + sigCD = port(muxAB, \B); + } + if (muxB) { muxAB = muxB; - if (muxA || muxB) + sigCD = port(muxAB, \A); + } + if (muxA || muxB) { sigO = port(muxAB, \Y); + sigCD_signed = addAB && param(addAB, \A_SIGNED).as_bool() && param(addAB, \B_SIGNED).as_bool(); + } endcode match ffO_lo -- cgit v1.2.3 From dc0c853abeadd11e81da280c657fd1341405de3b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 23 Jul 2019 14:20:34 -0700 Subject: Simplify and fix for MACs --- passes/pmgen/ice40_dsp.cc | 61 +++++++++++++++------------------------------- passes/pmgen/ice40_dsp.pmg | 33 +++++++++++++------------ 2 files changed, 38 insertions(+), 56 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index f365ae8b6..f18fad060 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -81,25 +81,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm) SigSpec B = st.sigB; B.extend_u0(16, b_signed); - SigSpec CD; - bool CD_signed = false; - if (st.muxAB != st.addAB) { - if (st.muxA) - CD = st.muxA->getPort("\\B"); - else if (st.muxB) - CD = st.muxB->getPort("\\A"); - else log_abort(); - CD_signed = a_signed && b_signed; // TODO: Do muxes have [AB]_SIGNED? - } - else if (st.addAB) { - if (st.addA) - CD = st.addAB->getPort("\\B"); - else if (st.addB) - CD = st.addAB->getPort("\\A"); - else log_abort(); - CD_signed = st.sigO_signed; - } - CD.extend_u0(32, CD_signed); + SigSpec CD = st.sigCD; + CD.extend_u0(32, st.sigCD_signed); cell->setPort("\\A", A); cell->setPort("\\B", B); @@ -161,27 +144,19 @@ void create_ice40_dsp(ice40_dsp_pm &pm) // SB_MAC16 Output Interface - SigSpec O_lo = (st.ffO_lo ? st.sigO : (st.addAB ? st.addAB->getPort("\\Y") : st.sigH)).extract(0,16); - if (GetSize(O_lo) < 16) - O_lo.append(pm.module->addWire(NEW_ID, 16-GetSize(O_lo))); - SigSpec O_hi = (st.ffO_hi ? st.sigO : (st.addAB ? st.addAB->getPort("\\Y") : st.sigH)).extract(16,16); - if (GetSize(O_hi) < 16) - O_hi.append(pm.module->addWire(NEW_ID, 16-GetSize(O_hi))); - - SigSpec O{O_hi,O_lo}; - cell->setPort("\\O", O); + cell->setPort("\\O", st.sigO); bool accum = false; if (st.addAB) { - if (st.addA) - accum = (st.ffO_lo && st.ffO_hi && st.addAB->getPort("\\B") == O); - else if (st.addB) - accum = (st.ffO_lo && st.ffO_hi && st.addAB->getPort("\\A") == O); - else log_abort(); - if (accum) - log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); - else - log(" adder %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); + if (st.addA) + accum = (st.ffO_lo && st.ffO_hi && st.addAB->getPort("\\B") == st.sigO); + else if (st.addB) + accum = (st.ffO_lo && st.ffO_hi && st.addAB->getPort("\\A") == st.sigO); + else log_abort(); + if (accum) + log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); + else + log(" adder %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); cell->setPort("\\ADDSUBTOP", st.addAB->type == "$add" ? State::S0 : State::S1); cell->setPort("\\ADDSUBBOT", st.addAB->type == "$add" ? State::S0 : State::S1); } else { @@ -231,10 +206,14 @@ void create_ice40_dsp(ice40_dsp_pm &pm) pm.autoremove(st.mul); pm.autoremove(st.ffH); pm.autoremove(st.addAB); - if (st.ffO_lo) - st.ffO_lo->connections_.at("\\Q").replace(O.extract(0,16), pm.module->addWire(NEW_ID, 16)); - if (st.ffO_hi) - st.ffO_hi->connections_.at("\\Q").replace(O.extract(16,16), pm.module->addWire(NEW_ID, 16)); + if (st.ffO_lo) { + SigSpec O = st.sigO.extract(0,16); + st.ffO_lo->connections_.at("\\Q").replace(O, pm.module->addWire(NEW_ID, GetSize(O))); + } + if (st.ffO_hi) { + SigSpec O = st.sigO.extract(16,16); + st.ffO_hi->connections_.at("\\Q").replace(O, pm.module->addWire(NEW_ID, GetSize(O))); + } } struct Ice40DspPass : public Pass { diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 73ece6962..24247d3cf 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -120,7 +120,6 @@ code addAB sigCD sigCD_signed sigO endcode match muxA - if sigCD.empty() select muxA->type.in($mux) select nusers(port(muxA, \A)) == 2 index port(muxA, \A) === sigO @@ -128,7 +127,6 @@ match muxA endmatch match muxB - if sigCD.empty() if !muxA select muxB->type.in($mux) select nusers(port(muxB, \B)) == 2 @@ -136,20 +134,11 @@ match muxB optional endmatch -code muxAB sigCD sigCD_signed sigO - muxAB = addAB; - if (muxA) { +code muxAB + if (muxA) muxAB = muxA; - sigCD = port(muxAB, \B); - } - if (muxB) { + else if (muxB) muxAB = muxB; - sigCD = port(muxAB, \A); - } - if (muxA || muxB) { - sigO = port(muxAB, \Y); - sigCD_signed = addAB && param(addAB, \A_SIGNED).as_bool() && param(addAB, \B_SIGNED).as_bool(); - } endcode match ffO_lo @@ -166,7 +155,7 @@ match ffO_hi optional endmatch -code clock clock_pol sigO +code clock clock_pol sigO sigCD sigCD_signed if (ffO_lo || ffO_hi) { if (ffO_lo) { SigBit c = port(ffO_lo, \CLK).as_bit(); @@ -195,5 +184,19 @@ code clock clock_pol sigO if (port(ffO_hi, \Q) != sigO.extract(16,16)) sigO.replace(port(ffO_hi, \D), port(ffO_hi, \Q)); } + + // Loading value into output register is not + // supported unless using accumulator + if (muxAB && sigCD != sigO) { + if (muxAB != addAB) + reject; + + if (muxA) + sigCD = port(muxAB, \B); + else if (muxB) + sigCD = port(muxAB, \A); + else log_abort(); + sigCD_signed = addAB && param(addAB, \A_SIGNED).as_bool() && param(addAB, \B_SIGNED).as_bool(); + } } endcode -- cgit v1.2.3 From 0dd2a125f655c459b17b5c56c4d34a21d0833bc8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 23 Jul 2019 14:21:45 -0700 Subject: Remove debug print --- passes/pmgen/ice40_dsp.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index f18fad060..ee4e4f5e8 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -32,7 +32,7 @@ void create_ice40_dsp(ice40_dsp_pm &pm) { auto &st = pm.st_ice40_dsp; -#if 1 +#if 0 log("\n"); log("ffA: %s\n", log_id(st.ffA, "--")); log("ffB: %s\n", log_id(st.ffB, "--")); -- cgit v1.2.3 From a37574ccbfe047c09a60bb6ee68b7b5e2ef61337 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 23 Jul 2019 14:52:14 -0700 Subject: Fix muxAB logic --- passes/pmgen/ice40_dsp.pmg | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 24247d3cf..4b566f0a6 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -187,10 +187,9 @@ code clock clock_pol sigO sigCD sigCD_signed // Loading value into output register is not // supported unless using accumulator - if (muxAB && sigCD != sigO) { - if (muxAB != addAB) + if (muxAB) { + if (sigCD != sigO) reject; - if (muxA) sigCD = port(muxAB, \B); else if (muxB) -- cgit v1.2.3 From 79fd6edc5a076d263a9d68f0e1a103a9d643a9df Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 23 Jul 2019 15:13:30 -0700 Subject: Eliminate warnings by sizing O correctly --- passes/pmgen/ice40_dsp.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index ee4e4f5e8..3ceffdbf6 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -144,7 +144,11 @@ void create_ice40_dsp(ice40_dsp_pm &pm) // SB_MAC16 Output Interface - cell->setPort("\\O", st.sigO); + SigSpec O = st.sigO; + if (GetSize(O) < 32) + O.append(pm.module->addWire(NEW_ID, 32-GetSize(O))); + + cell->setPort("\\O", O); bool accum = false; if (st.addAB) { -- cgit v1.2.3 From c1a05f45577223c0585e93d728c8e04169c4598d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 26 Jul 2019 10:15:36 -0700 Subject: Allow adders/accumulators with 33 bits using CO output --- passes/pmgen/ice40_dsp.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 3ceffdbf6..c5655ad20 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -56,8 +56,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm) return; } - if (GetSize(st.sigO) > 32) { - log(" accumulator (%s) is too large (%d > 32).\n", log_signal(st.sigO), GetSize(st.sigO)); + if (GetSize(st.sigO) > 33) { + log(" adder/accumulator (%s) is too large (%d > 33).\n", log_signal(st.sigO), GetSize(st.sigO)); return; } @@ -137,7 +137,6 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setPort("\\SIGNEXTOUT", pm.module->addWire(NEW_ID)); cell->setPort("\\CI", State::Sx); - cell->setPort("\\CO", pm.module->addWire(NEW_ID)); cell->setPort("\\ACCUMCI", State::Sx); cell->setPort("\\ACCUMCO", pm.module->addWire(NEW_ID)); @@ -145,6 +144,12 @@ void create_ice40_dsp(ice40_dsp_pm &pm) // SB_MAC16 Output Interface SigSpec O = st.sigO; + if (GetSize(O) == 33) + cell->setPort("\\CO", st.sigO[32]); + else { + log_assert(GetSize(O) <= 32); + cell->setPort("\\CO", pm.module->addWire(NEW_ID)); + } if (GetSize(O) < 32) O.append(pm.module->addWire(NEW_ID, 32-GetSize(O))); -- cgit v1.2.3 From 4c25d1a76fc006cac0d9e2038617f41ca90685c1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 26 Jul 2019 10:27:30 -0700 Subject: Pop the CO bit from O --- passes/pmgen/ice40_dsp.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index c5655ad20..369cb211e 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -144,8 +144,10 @@ void create_ice40_dsp(ice40_dsp_pm &pm) // SB_MAC16 Output Interface SigSpec O = st.sigO; - if (GetSize(O) == 33) + if (GetSize(O) == 33) { cell->setPort("\\CO", st.sigO[32]); + O.remove(32); + } else { log_assert(GetSize(O) <= 32); cell->setPort("\\CO", pm.module->addWire(NEW_ID)); -- cgit v1.2.3 From 8cecad5059b7ce6e1db1597020794c8e8aad3e49 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 26 Jul 2019 12:26:54 -0700 Subject: Add doc for "test_autotb -seed" option --- passes/tests/test_autotb.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'passes') diff --git a/passes/tests/test_autotb.cc b/passes/tests/test_autotb.cc index bfb1d6642..7eee6a568 100644 --- a/passes/tests/test_autotb.cc +++ b/passes/tests/test_autotb.cc @@ -348,6 +348,9 @@ struct TestAutotbBackend : public Backend { log(" -n \n"); log(" number of iterations the test bench should run (default = 1000)\n"); log("\n"); + log(" -seed \n"); + log(" seed used for pseudo-random number generation (default = time)\n"); + log("\n"); } void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE { -- cgit v1.2.3 From 07e38d8d5c9d270404f68072b905b1dd43ced24b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 26 Jul 2019 12:37:30 -0700 Subject: Update test_autotb doc to reflect default value of zero --- passes/tests/test_autotb.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/tests/test_autotb.cc b/passes/tests/test_autotb.cc index 7eee6a568..7f11e54f3 100644 --- a/passes/tests/test_autotb.cc +++ b/passes/tests/test_autotb.cc @@ -349,7 +349,9 @@ struct TestAutotbBackend : public Backend { log(" number of iterations the test bench should run (default = 1000)\n"); log("\n"); log(" -seed \n"); - log(" seed used for pseudo-random number generation (default = time)\n"); + log(" seed used for pseudo-random number generation (default = 0).\n"); + log(" a value of 0 will cause an arbitrary seed to be chosen, based on\n"); + log(" the current system time.\n"); log("\n"); } void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE -- cgit v1.2.3 From e4a638c29297e3e8b915cf84a2dddc339f511476 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 31 Jul 2019 15:45:15 -0700 Subject: Restore old CO behaviour --- passes/pmgen/ice40_dsp.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 369cb211e..00794ca0d 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -144,14 +144,15 @@ void create_ice40_dsp(ice40_dsp_pm &pm) // SB_MAC16 Output Interface SigSpec O = st.sigO; - if (GetSize(O) == 33) { - cell->setPort("\\CO", st.sigO[32]); - O.remove(32); + int O_width = GetSize(O); + if (O_width == 33) { + log_assert(st.addAB); + cell->setPort("\\CO", O[-1]); + O.remove(O_width-1); } - else { - log_assert(GetSize(O) <= 32); + else cell->setPort("\\CO", pm.module->addWire(NEW_ID)); - } + log_assert(GetSize(O) <= 32); if (GetSize(O) < 32) O.append(pm.module->addWire(NEW_ID, 32-GetSize(O))); -- cgit v1.2.3 From e3c39cc450a0317ad7e8234bb866d55465548c9c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 1 Aug 2019 10:00:01 -0700 Subject: Fix typo --- passes/pmgen/ice40_dsp.pmg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 4b566f0a6..73439cfd9 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -112,7 +112,7 @@ code addAB sigCD sigCD_signed sigO if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width)) reject; - if ((actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(addAB, \A_SIGNED).as_bool())) + if ((actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(addAB, \B_SIGNED).as_bool())) reject; sigO = port(addAB, \Y); -- cgit v1.2.3 From c54a39069d1f536da7a830fa2fa504bc72c20c18 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 1 Aug 2019 10:00:49 -0700 Subject: CO is sign extension only if signed multiplier --- passes/pmgen/ice40_dsp.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 00794ca0d..f88cd62dd 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -147,7 +147,12 @@ void create_ice40_dsp(ice40_dsp_pm &pm) int O_width = GetSize(O); if (O_width == 33) { log_assert(st.addAB); - cell->setPort("\\CO", O[-1]); + // If we have a signed multiply-add, then perform sign extension + // TODO: Need to check CD[31:16] is sign extension of CD[15:0]? + if (st.addAB->getParam("\\A_SIGNED").as_bool() && st.addAB->getParam("\\B_SIGNED").as_bool()) + pm.module->connect(O[-1], O[-2]); + else + cell->setPort("\\CO", O[-1]); O.remove(O_width-1); } else -- cgit v1.2.3 From e19d33b003702a03b191fa2eda14d016a6bce0aa Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 1 Aug 2019 12:44:56 -0700 Subject: Cope with sign extension in mul2dsp --- passes/pmgen/ice40_dsp.cc | 16 ++++++++-------- passes/pmgen/ice40_dsp.pmg | 12 ++++++------ 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index f88cd62dd..f6ae3a13f 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -72,17 +72,17 @@ void create_ice40_dsp(ice40_dsp_pm &pm) pm.module->swap_names(cell, st.mul); // SB_MAC16 Input Interface - bool a_signed = st.mul->getParam("\\A_SIGNED").as_bool(); - bool b_signed = st.mul->getParam("\\B_SIGNED").as_bool(); - SigSpec A = st.sigA; - A.extend_u0(16, a_signed); + log_assert(GetSize(A) == 16); SigSpec B = st.sigB; - B.extend_u0(16, b_signed); + log_assert(GetSize(B) == 16); SigSpec CD = st.sigCD; - CD.extend_u0(32, st.sigCD_signed); + if (CD.empty()) + CD = RTLIL::Const(0, 32); + else + log_assert(GetSize(CD) == 32); cell->setPort("\\A", A); cell->setPort("\\B", B); @@ -217,8 +217,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2)); cell->setParam("\\MODE_8x8", State::S0); - cell->setParam("\\A_SIGNED", a_signed); - cell->setParam("\\B_SIGNED", b_signed); + cell->setParam("\\A_SIGNED", st.mul->getParam("\\A_SIGNED").as_bool()); + cell->setParam("\\B_SIGNED", st.mul->getParam("\\B_SIGNED").as_bool()); pm.autoremove(st.mul); pm.autoremove(st.ffH); diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 73439cfd9..040332539 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -1,7 +1,7 @@ pattern ice40_dsp state clock -state clock_pol sigCD_signed +state clock_pol state sigA sigB sigCD sigH sigO state addAB muxAB @@ -94,16 +94,16 @@ match addB optional endmatch -code addAB sigCD sigCD_signed sigO +code addAB sigCD sigO if (addA) { addAB = addA; sigCD = port(addAB, \B); - sigCD_signed = param(addAB, \B_SIGNED).as_bool(); + sigCD.extend_u0(32, param(addAB, \B_SIGNED).as_bool()); } if (addB) { addAB = addB; sigCD = port(addAB, \A); - sigCD_signed = param(addAB, \A_SIGNED).as_bool(); + sigCD.extend_u0(32, param(addAB, \A_SIGNED).as_bool()); } if (addAB) { int natural_mul_width = GetSize(sigA) + GetSize(sigB); @@ -155,7 +155,7 @@ match ffO_hi optional endmatch -code clock clock_pol sigO sigCD sigCD_signed +code clock clock_pol sigO sigCD if (ffO_lo || ffO_hi) { if (ffO_lo) { SigBit c = port(ffO_lo, \CLK).as_bit(); @@ -195,7 +195,7 @@ code clock clock_pol sigO sigCD sigCD_signed else if (muxB) sigCD = port(muxAB, \A); else log_abort(); - sigCD_signed = addAB && param(addAB, \A_SIGNED).as_bool() && param(addAB, \B_SIGNED).as_bool(); + sigCD.extend_u0(32, addAB && param(addAB, \A_SIGNED).as_bool() && param(addAB, \B_SIGNED).as_bool()); } } endcode -- cgit v1.2.3 From ed7540a46f22151d6c87205df92bc52f5e875130 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 1 Aug 2019 15:10:43 -0700 Subject: Pack P register properly --- passes/pmgen/xilinx_dsp.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index d87d63670..be510b4cb 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -86,14 +86,16 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) else D = st.ffP->getPort("\\D"); SigSpec Q = st.ffP->getPort("\\Q"); - P.replace(D, Q); - cell->setPort("\\P", Q); + P.replace(pm.sigmap(D), Q); + cell->setPort("\\P", P); cell->setParam("\\PREG", State::S1); if (st.ffP->type == "$dff") cell->setPort("\\CEP", State::S1); else if (st.ffP->type == "$dffe") cell->setPort("\\CEP", st.ffP->getPort("\\EN")); else log_abort(); + + st.ffP->connections_.at("\\Q").replace(P, pm.module->addWire(NEW_ID, GetSize(P))); } log(" clock: %s (%s)", log_signal(st.clock), "posedge"); -- cgit v1.2.3 From c39b1a6fcf648203df10d640c72e073f455ddc32 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 1 Aug 2019 15:13:18 -0700 Subject: Add comment about supporting $dffe in ice40_dsp --- passes/pmgen/ice40_dsp.pmg | 1 + 1 file changed, 1 insertion(+) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 040332539..b6da1d2f6 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -12,6 +12,7 @@ match mul endmatch match ffA + // TODO: Support $dffe too by checking if all enable signals are identical select ffA->type.in($dff) filter !port(mul, \A).remove_const().empty() filter includes(port(ffA, \Q).to_sigbit_set(), port(mul, \A).remove_const().to_sigbit_set()) -- cgit v1.2.3 From cdf9c801347693c273309694685b2080ef00fd02 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 7 Aug 2019 12:57:10 -0700 Subject: Do not pack registers if (* keep *) --- passes/pmgen/ice40_dsp.pmg | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index b6da1d2f6..f1f533187 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -23,6 +23,10 @@ code sigA clock clock_pol sigA = port(mul, \A); if (ffA) { + for (auto b : port(ffA, \Q)) + if (b.wire->get_bool_attribute(\keep)) + reject; + clock = port(ffA, \CLK).as_bit(); clock_pol = param(ffA, \CLK_POLARITY).as_bool(); @@ -41,6 +45,10 @@ code sigB clock clock_pol sigB = port(mul, \B); if (ffB) { + for (auto b : port(ffB, \Q)) + if (b.wire->get_bool_attribute(\keep)) + reject; + SigBit c = port(ffB, \CLK).as_bit(); bool cp = param(ffB, \CLK_POLARITY).as_bool(); @@ -67,6 +75,10 @@ code sigH sigO clock clock_pol if (ffH) { sigH = port(ffH, \Q); + for (auto b : sigH) + if (b.wire->get_bool_attribute(\keep)) + reject; + sigO = sigH; SigBit c = port(ffH, \CLK).as_bit(); @@ -159,6 +171,10 @@ endmatch code clock clock_pol sigO sigCD if (ffO_lo || ffO_hi) { if (ffO_lo) { + for (auto b : port(ffO_lo, \Q)) + if (b.wire->get_bool_attribute(\keep)) + reject; + SigBit c = port(ffO_lo, \CLK).as_bit(); bool cp = param(ffO_lo, \CLK_POLARITY).as_bool(); @@ -173,6 +189,10 @@ code clock clock_pol sigO sigCD } if (ffO_hi) { + for (auto b : port(ffO_hi, \Q)) + if (b.wire->get_bool_attribute(\keep)) + reject; + SigBit c = port(ffO_hi, \CLK).as_bit(); bool cp = param(ffO_hi, \CLK_POLARITY).as_bool(); -- cgit v1.2.3 From d90b8b081a6102303f2392fc21164fddde90e587 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 7 Aug 2019 13:58:26 -0700 Subject: Do not SigSpec::extract() beyond bounds --- passes/pmgen/ice40_dsp.cc | 4 ++-- passes/pmgen/ice40_dsp.pmg | 14 ++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index f6ae3a13f..5e87d6497 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -224,11 +224,11 @@ void create_ice40_dsp(ice40_dsp_pm &pm) pm.autoremove(st.ffH); pm.autoremove(st.addAB); if (st.ffO_lo) { - SigSpec O = st.sigO.extract(0,16); + SigSpec O = st.sigO.extract(0,GetSize(st.ffO_lo)); st.ffO_lo->connections_.at("\\Q").replace(O, pm.module->addWire(NEW_ID, GetSize(O))); } if (st.ffO_hi) { - SigSpec O = st.sigO.extract(16,16); + SigSpec O = st.sigO.extract(16,GetSize(st.ffo_hi)); st.ffO_hi->connections_.at("\\Q").replace(O, pm.module->addWire(NEW_ID, GetSize(O))); } } diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index f1f533187..8b1ac2563 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -156,15 +156,17 @@ endcode match ffO_lo select ffO_lo->type.in($dff) - filter nusers(sigO.extract(0,16)) == 2 - filter includes(port(ffO_lo, \D).to_sigbit_set(), sigO.extract(0,16).to_sigbit_set()) + filter GetSize(sigO) >= param(ffO_lo, \WIDTH).as_int() + filter nusers(sigO.extract(0,param(ffO_lo, \WIDTH).as_int())) == 2 + filter includes(port(ffO_lo, \D).to_sigbit_set(), sigO.extract(0,param(ffO_lo, \WIDTH).as_int()).to_sigbit_set()) optional endmatch match ffO_hi select ffO_hi->type.in($dff) - filter nusers(sigO.extract(16,16)) == 2 - filter includes(port(ffO_hi, \D).to_sigbit_set(), sigO.extract(16,16).to_sigbit_set()) + filter GetSize(sigO) >= 16+param(ffO_hi, \WIDTH).as_int() + filter nusers(sigO.extract(16,param(ffO_hi, \WIDTH).as_int())) == 2 + filter includes(port(ffO_hi, \D).to_sigbit_set(), sigO.extract(16,param(ffO_hi, \WIDTH).as_int()).to_sigbit_set()) optional endmatch @@ -184,7 +186,7 @@ code clock clock_pol sigO sigCD clock = c; clock_pol = cp; - if (port(ffO_lo, \Q) != sigO.extract(0,16)) + if (port(ffO_lo, \Q) != sigO.extract(0,param(ffO_lo, \WIDTH).as_int())) sigO.replace(port(ffO_lo, \D), port(ffO_lo, \Q)); } @@ -202,7 +204,7 @@ code clock clock_pol sigO sigCD clock = c; clock_pol = cp; - if (port(ffO_hi, \Q) != sigO.extract(16,16)) + if (port(ffO_hi, \Q) != sigO.extract(16,param(ffO_hi, \WIDTH).as_int())) sigO.replace(port(ffO_hi, \D), port(ffO_hi, \Q)); } -- cgit v1.2.3 From fb568ddb4e2ccaab352d9d062f6b4926aca75680 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 7 Aug 2019 14:31:55 -0700 Subject: Fix compile error --- passes/pmgen/ice40_dsp.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 5e87d6497..45d7a34df 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -224,11 +224,11 @@ void create_ice40_dsp(ice40_dsp_pm &pm) pm.autoremove(st.ffH); pm.autoremove(st.addAB); if (st.ffO_lo) { - SigSpec O = st.sigO.extract(0,GetSize(st.ffO_lo)); + SigSpec O = st.sigO.extract(0,st.ffO_lo->getParam("\\WIDTH").as_int()); st.ffO_lo->connections_.at("\\Q").replace(O, pm.module->addWire(NEW_ID, GetSize(O))); } if (st.ffO_hi) { - SigSpec O = st.sigO.extract(16,GetSize(st.ffo_hi)); + SigSpec O = st.sigO.extract(16,st.ffO_hi->getParam("\\WIDTH").as_int()); st.ffO_hi->connections_.at("\\Q").replace(O, pm.module->addWire(NEW_ID, GetSize(O))); } } -- cgit v1.2.3 From 911129e3ef9196a2f775d97746d704ed761da40d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 8 Aug 2019 10:44:49 -0700 Subject: Disable $dffe --- passes/pmgen/xilinx_dsp.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index be510b4cb..74bcbf451 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -58,11 +58,11 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) SigSpec Q = st.ffA->getPort("\\Q"); A.replace(Q, D); cell->setPort("\\A", A); - cell->setParam("\\AREG", State::S1); + cell->setParam("\\AREG", 1); if (st.ffA->type == "$dff") cell->setPort("\\CEA2", State::S1); - else if (st.ffA->type == "$dffe") - cell->setPort("\\CEA2", st.ffA->getPort("\\EN")); + //else if (st.ffA->type == "$dffe") + // cell->setPort("\\CEA2", st.ffA->getPort("\\EN")); else log_abort(); } if (st.ffB) { @@ -71,11 +71,11 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) SigSpec Q = st.ffB->getPort("\\Q"); B.replace(Q, D); cell->setPort("\\B", B); - cell->setParam("\\BREG", State::S1); + cell->setParam("\\BREG", 1); if (st.ffB->type == "$dff") cell->setPort("\\CEB2", State::S1); - else if (st.ffB->type == "$dffe") - cell->setPort("\\CEB2", st.ffB->getPort("\\EN")); + //else if (st.ffB->type == "$dffe") + // cell->setPort("\\CEB2", st.ffB->getPort("\\EN")); else log_abort(); } if (st.ffP) { @@ -91,8 +91,8 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) cell->setParam("\\PREG", State::S1); if (st.ffP->type == "$dff") cell->setPort("\\CEP", State::S1); - else if (st.ffP->type == "$dffe") - cell->setPort("\\CEP", st.ffP->getPort("\\EN")); + //else if (st.ffP->type == "$dffe") + // cell->setPort("\\CEP", st.ffP->getPort("\\EN")); else log_abort(); st.ffP->connections_.at("\\Q").replace(P, pm.module->addWire(NEW_ID, GetSize(P))); -- cgit v1.2.3 From 07e50b9c256358b2800a5272258a083f7e4d67d3 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 8 Aug 2019 10:51:19 -0700 Subject: Only pack registers if {A,B,P}REG = 0, do not pack $dffe --- passes/pmgen/xilinx_dsp.pmg | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index a97ab4dd5..6fd1207fa 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -8,9 +8,10 @@ match dsp endmatch match ffA - select ffA->type.in($dff, $dffe) + select ffA->type.in($dff) // DSP48E1 does not support clock inversion select param(ffA, \CLK_POLARITY).as_bool() + filter param(dsp, \AREG).as_int() == 0 filter !port(dsp, \A).remove_const().empty() filter includes(port(ffA, \Q).to_sigbit_set(), port(dsp, \A).remove_const().to_sigbit_set()) optional @@ -22,9 +23,10 @@ code clock endcode match ffB - select ffB->type.in($dff, $dffe) + select ffB->type.in($dff) // DSP48E1 does not support clock inversion select param(ffB, \CLK_POLARITY).as_bool() + filter param(dsp, \BREG).as_int() == 0 filter !port(dsp, \B).remove_const().empty() filter includes(port(ffB, \Q).to_sigbit_set(), port(dsp, \B).remove_const().to_sigbit_set()) optional @@ -54,10 +56,11 @@ endcode match ffP if !sigPused.empty() - select ffP->type.in($dff, $dffe) + select ffP->type.in($dff) select nusers(port(ffP, \D)) == 2 // DSP48E1 does not support clock inversion select param(ffP, \CLK_POLARITY).as_bool() + filter param(dsp, \PREG).as_int() == 0 filter param(ffP, \WIDTH).as_int() >= GetSize(sigPused) filter includes(port(ffP, \D).to_sigbit_set(), sigPused.to_sigbit_set()) optional -- cgit v1.2.3 From 2c0be7aa5d7dcdf18678fb7b09ba1b3b5dd00998 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 8 Aug 2019 12:56:05 -0700 Subject: Rework ice40_dsp to map to SB_MAC16 earlier, and check before packing --- passes/pmgen/ice40_dsp.cc | 21 ++++++---- passes/pmgen/ice40_dsp.pmg | 99 +++++++++++++++++++++++++++++++-------------- passes/pmgen/xilinx_dsp.pmg | 2 +- 3 files changed, 83 insertions(+), 39 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 45d7a34df..bb45b8a4e 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -32,7 +32,7 @@ void create_ice40_dsp(ice40_dsp_pm &pm) { auto &st = pm.st_ice40_dsp; -#if 0 +#if 1 log("\n"); log("ffA: %s\n", log_id(st.ffA, "--")); log("ffB: %s\n", log_id(st.ffB, "--")); @@ -66,10 +66,14 @@ void create_ice40_dsp(ice40_dsp_pm &pm) return; } - log(" replacing %s with SB_MAC16 cell.\n", log_id(st.mul->type)); + Cell *cell = st.mul; + if (cell->type == "$mul") { + log(" replacing %s with SB_MAC16 cell.\n", log_id(st.mul->type)); - Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16"); - pm.module->swap_names(cell, st.mul); + cell = pm.module->addCell(NEW_ID, "\\SB_MAC16"); + pm.module->swap_names(cell, st.mul); + } + else log_assert(cell->type == "\\SB_MAC16"); // SB_MAC16 Input Interface SigSpec A = st.sigA; @@ -220,15 +224,18 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam("\\A_SIGNED", st.mul->getParam("\\A_SIGNED").as_bool()); cell->setParam("\\B_SIGNED", st.mul->getParam("\\B_SIGNED").as_bool()); - pm.autoremove(st.mul); + if (cell != st.mul) + pm.autoremove(st.mul); + else + pm.blacklist(st.mul); pm.autoremove(st.ffH); pm.autoremove(st.addAB); if (st.ffO_lo) { - SigSpec O = st.sigO.extract(0,st.ffO_lo->getParam("\\WIDTH").as_int()); + SigSpec O = st.sigO.extract(0,std::min(16,st.ffO_lo->getParam("\\WIDTH").as_int())); st.ffO_lo->connections_.at("\\Q").replace(O, pm.module->addWire(NEW_ID, GetSize(O))); } if (st.ffO_hi) { - SigSpec O = st.sigO.extract(16,st.ffO_hi->getParam("\\WIDTH").as_int()); + SigSpec O = st.sigO.extract_end(16); st.ffO_hi->connections_.at("\\Q").replace(O, pm.module->addWire(NEW_ID, GetSize(O))); } } diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 8b1ac2563..1a62c7bda 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -2,18 +2,27 @@ pattern ice40_dsp state clock state clock_pol -state sigA sigB sigCD sigH sigO +state sigA sigB sigCD sigH sigO sigOused state addAB muxAB match mul - select mul->type.in($mul, $__MUL16X16) + select mul->type.in($mul, \SB_MAC16) select GetSize(mul->getPort(\A)) + GetSize(mul->getPort(\B)) > 10 - select GetSize(mul->getPort(\Y)) > 10 endmatch +code sigH + if (mul->type == $mul) + sigH = mul->getPort(\Y); + else if (mul->type == \SB_MAC16) + sigH = mul->getPort(\O); + else log_abort(); + if (GetSize(sigH) <= 10) + reject; +endcode + match ffA - // TODO: Support $dffe too by checking if all enable signals are identical select ffA->type.in($dff) + filter mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool() filter !port(mul, \A).remove_const().empty() filter includes(port(ffA, \Q).to_sigbit_set(), port(mul, \A).remove_const().to_sigbit_set()) optional @@ -23,9 +32,9 @@ code sigA clock clock_pol sigA = port(mul, \A); if (ffA) { - for (auto b : port(ffA, \Q)) - if (b.wire->get_bool_attribute(\keep)) - reject; + for (auto b : port(ffA, \Q)) + if (b.wire->get_bool_attribute(\keep)) + reject; clock = port(ffA, \CLK).as_bit(); clock_pol = param(ffA, \CLK_POLARITY).as_bool(); @@ -36,6 +45,7 @@ endcode match ffB select ffB->type.in($dff) + filter mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool() filter !port(mul, \B).remove_const().empty() filter includes(port(ffB, \Q).to_sigbit_set(), port(mul, \B).remove_const().to_sigbit_set()) optional @@ -45,9 +55,9 @@ code sigB clock clock_pol sigB = port(mul, \B); if (ffB) { - for (auto b : port(ffB, \Q)) - if (b.wire->get_bool_attribute(\keep)) - reject; + for (auto b : port(ffB, \Q)) + if (b.wire->get_bool_attribute(\keep)) + reject; SigBit c = port(ffB, \CLK).as_bit(); bool cp = param(ffB, \CLK_POLARITY).as_bool(); @@ -65,19 +75,20 @@ endcode match ffH select ffH->type.in($dff) select nusers(port(ffH, \D)) == 2 - index port(ffH, \D) === port(mul, \Y) + index port(ffH, \D) === sigH + // Ensure pipeline register is not already used + filter mul->type != \SB_MAC16 || (!param(mul, \TOP_8x8_MULT_REG).as_bool() && !param(mul, \BOT_8x8_MULT_REG).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG2).as_bool()) optional endmatch code sigH sigO clock clock_pol - sigH = port(mul, \Y); sigO = sigH; if (ffH) { sigH = port(ffH, \Q); - for (auto b : sigH) - if (b.wire->get_bool_attribute(\keep)) - reject; + for (auto b : sigH) + if (b.wire->get_bool_attribute(\keep)) + reject; sigO = sigH; @@ -119,6 +130,13 @@ code addAB sigCD sigO sigCD.extend_u0(32, param(addAB, \A_SIGNED).as_bool()); } if (addAB) { + if (mul->type == \SB_MAC16) { + // Ensure that adder is not used + if (param(mul, \TOPOUTPUT_SELECT).as_int() != 3 || + param(mul, \BOTOUTPUT_SELECT).as_int() != 3) + reject; + } + int natural_mul_width = GetSize(sigA) + GetSize(sigB); int actual_mul_width = GetSize(sigH); int actual_acc_width = GetSize(sigO); @@ -154,28 +172,49 @@ code muxAB muxAB = muxB; endcode +// Extract the bits of P that actually have a consumer +// (as opposed to being a dummy) +code sigOused + for (int i = 0; i < GetSize(sigO); i++) + if (!sigO[i].wire || nusers(sigO[i]) == 1) + sigOused.append(State::Sx); + else + sigOused.append(sigO[i]); +endcode + match ffO_lo select ffO_lo->type.in($dff) - filter GetSize(sigO) >= param(ffO_lo, \WIDTH).as_int() - filter nusers(sigO.extract(0,param(ffO_lo, \WIDTH).as_int())) == 2 - filter includes(port(ffO_lo, \D).to_sigbit_set(), sigO.extract(0,param(ffO_lo, \WIDTH).as_int()).to_sigbit_set()) + filter nusers(sigOused.extract(0,std::min(16,param(ffO_lo, \WIDTH).as_int()))) == 2 + filter includes(port(ffO_lo, \D).to_sigbit_set(), sigOused.extract(0,std::min(16,param(ffO_lo, \WIDTH).as_int())).remove_const().to_sigbit_set()) optional endmatch match ffO_hi select ffO_hi->type.in($dff) - filter GetSize(sigO) >= 16+param(ffO_hi, \WIDTH).as_int() - filter nusers(sigO.extract(16,param(ffO_hi, \WIDTH).as_int())) == 2 - filter includes(port(ffO_hi, \D).to_sigbit_set(), sigO.extract(16,param(ffO_hi, \WIDTH).as_int()).to_sigbit_set()) + filter GetSize(sigOused) > 16 + filter nusers(sigOused.extract_end(16)) == 2 + filter includes(port(ffO_hi, \D).to_sigbit_set(), sigOused.extract_end(16).remove_const().to_sigbit_set()) optional endmatch code clock clock_pol sigO sigCD if (ffO_lo || ffO_hi) { + if (mul->type == \SB_MAC16) { + // Ensure that register is not already used + if (param(mul, \TOPOUTPUT_SELECT).as_int() == 1 || + param(mul, \BOTOUTPUT_SELECT).as_int() == 1) + reject; + + // Ensure that OLOADTOP/OLOADBOT is unused or zero + if ((mul->hasPort(\OLOADTOP) && !port(mul, \OLOADTOP).is_fully_zero()) + || (mul->hasPort(\OLOADBOT) && !port(mul, \OLOADBOT).is_fully_zero())) + reject; + } + if (ffO_lo) { - for (auto b : port(ffO_lo, \Q)) - if (b.wire->get_bool_attribute(\keep)) - reject; + for (auto b : port(ffO_lo, \Q)) + if (b.wire->get_bool_attribute(\keep)) + reject; SigBit c = port(ffO_lo, \CLK).as_bit(); bool cp = param(ffO_lo, \CLK_POLARITY).as_bool(); @@ -186,14 +225,13 @@ code clock clock_pol sigO sigCD clock = c; clock_pol = cp; - if (port(ffO_lo, \Q) != sigO.extract(0,param(ffO_lo, \WIDTH).as_int())) - sigO.replace(port(ffO_lo, \D), port(ffO_lo, \Q)); + sigO.replace(port(ffO_lo, \D), port(ffO_lo, \Q)); } if (ffO_hi) { - for (auto b : port(ffO_hi, \Q)) - if (b.wire->get_bool_attribute(\keep)) - reject; + for (auto b : port(ffO_hi, \Q)) + if (b.wire->get_bool_attribute(\keep)) + reject; SigBit c = port(ffO_hi, \CLK).as_bit(); bool cp = param(ffO_hi, \CLK_POLARITY).as_bool(); @@ -204,8 +242,7 @@ code clock clock_pol sigO sigCD clock = c; clock_pol = cp; - if (port(ffO_hi, \Q) != sigO.extract(16,param(ffO_hi, \WIDTH).as_int())) - sigO.replace(port(ffO_hi, \D), port(ffO_hi, \Q)); + sigO.replace(port(ffO_hi, \D), port(ffO_hi, \Q)); } // Loading value into output register is not diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 6fd1207fa..8abae9316 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -44,7 +44,7 @@ code clock endcode // Extract the bits of P that actually have a consumer -// (as opposed to being a sign extension) +// (as opposed to being a dummy) code sigPused SigSpec P = port(dsp, \P); int i; -- cgit v1.2.3 From 747690a6df9e51b4065003b50b0f07042712f112 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 8 Aug 2019 16:33:37 -0700 Subject: Remove muxY and ffY for now --- passes/pmgen/xilinx_dsp.cc | 10 ++++---- passes/pmgen/xilinx_dsp.pmg | 58 ++++++++++++++++++++++----------------------- 2 files changed, 33 insertions(+), 35 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 74bcbf451..389f0cb56 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -38,7 +38,7 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) log("ffB: %s\n", log_id(st.ffB, "--")); log("dsp: %s\n", log_id(st.dsp, "--")); log("ffP: %s\n", log_id(st.ffP, "--")); - log("muxP: %s\n", log_id(st.muxP, "--")); + //log("muxP: %s\n", log_id(st.muxP, "--")); log("sigPused: %s\n", log_signal(st.sigPused)); log_module(pm.module); #endif @@ -81,9 +81,9 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) if (st.ffP) { SigSpec P = cell->getPort("\\P"); SigSpec D; - if (st.muxP) - D = st.muxP->getPort("\\B"); - else + //if (st.muxP) + // D = st.muxP->getPort("\\B"); + //else D = st.ffP->getPort("\\D"); SigSpec Q = st.ffP->getPort("\\Q"); P.replace(pm.sigmap(D), Q); @@ -107,7 +107,7 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) log(" ffB:%s", log_id(st.ffB)); if (st.ffP) - log(" ffY:%s", log_id(st.ffP)); + log(" ffP:%s", log_id(st.ffP)); log("\n"); } diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 8abae9316..f95de9410 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -47,11 +47,9 @@ endcode // (as opposed to being a dummy) code sigPused SigSpec P = port(dsp, \P); - int i; - for (i = GetSize(P); i > 0; i--) - if (nusers(P[i-1]) > 1) - break; - sigPused = P.extract(0, i).remove_const(); + for (int i = 0; i < GetSize(P); i++) + if (P[i].wire && nusers(P[i]) > 1) + sigPused.append(P[i]); endcode match ffP @@ -66,33 +64,33 @@ match ffP optional endmatch -// $mux cell left behind by dff2dffe -// would prefer not to run 'opt_expr -mux_undef' -// since that would lose information helpful for -// efficient wide-mux inference -match muxP - if !sigPused.empty() && !ffP - select muxP->type.in($mux) - select nusers(port(muxP, \B)) == 2 - select port(muxP, \A).is_fully_undef() - filter param(muxP, \WIDTH).as_int() >= GetSize(sigPused) - filter includes(port(muxP, \B).to_sigbit_set(), sigPused.to_sigbit_set()) - optional -endmatch - -match ffY - if muxP - select ffY->type.in($dff, $dffe) - select nusers(port(ffY, \D)) == 2 - // DSP48E1 does not support clock inversion - select param(ffY, \CLK_POLARITY).as_bool() - filter param(ffY, \WIDTH).as_int() >= GetSize(sigPused) - filter includes(port(ffY, \D).to_sigbit_set(), port(muxP, \Y).to_sigbit_set()) -endmatch +//// $mux cell left behind by dff2dffe +//// would prefer not to run 'opt_expr -mux_undef' +//// since that would lose information helpful for +//// efficient wide-mux inference +//match muxP +// if !sigPused.empty() && !ffP +// select muxP->type.in($mux) +// select nusers(port(muxP, \B)) == 2 +// select port(muxP, \A).is_fully_undef() +// filter param(muxP, \WIDTH).as_int() >= GetSize(sigPused) +// filter includes(port(muxP, \B).to_sigbit_set(), sigPused.to_sigbit_set()) +// optional +//endmatch +// +//match ffY +// if muxP +// select ffY->type.in($dff, $dffe) +// select nusers(port(ffY, \D)) == 2 +// // DSP48E1 does not support clock inversion +// select param(ffY, \CLK_POLARITY).as_bool() +// filter param(ffY, \WIDTH).as_int() >= GetSize(sigPused) +// filter includes(port(ffY, \D).to_sigbit_set(), port(muxP, \Y).to_sigbit_set()) +//endmatch code ffP clock - if (ffY) - ffP = ffY; +// if (ffY) +// ffP = ffY; if (ffP) { SigBit c = port(ffP, \CLK).as_bit(); -- cgit v1.2.3 From 82cbfada1bd826fad2407010ceb243ab614ae875 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 9 Aug 2019 14:14:28 -0700 Subject: Revert "Fix typo" This reverts commit e3c39cc450a0317ad7e8234bb866d55465548c9c. --- passes/pmgen/ice40_dsp.pmg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 1a62c7bda..c57d3f1b3 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -143,7 +143,7 @@ code addAB sigCD sigO if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width)) reject; - if ((actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(addAB, \B_SIGNED).as_bool())) + if ((actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(addAB, \A_SIGNED).as_bool())) reject; sigO = port(addAB, \Y); -- cgit v1.2.3 From a002eba14a9895c7330a2741a49de02faf1af06f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 9 Aug 2019 14:27:08 -0700 Subject: Fix check --- passes/pmgen/ice40_dsp.pmg | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index c57d3f1b3..41f34b4bd 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -119,15 +119,16 @@ match addB endmatch code addAB sigCD sigO + bool CD_SIGNED = false; if (addA) { addAB = addA; sigCD = port(addAB, \B); - sigCD.extend_u0(32, param(addAB, \B_SIGNED).as_bool()); + CD_SIGNED = param(addAB, \B_SIGNED).as_bool(); } if (addB) { addAB = addB; sigCD = port(addAB, \A); - sigCD.extend_u0(32, param(addAB, \A_SIGNED).as_bool()); + CD_SIGNED = param(addAB, \A_SIGNED).as_bool(); } if (addAB) { if (mul->type == \SB_MAC16) { @@ -139,7 +140,7 @@ code addAB sigCD sigO int natural_mul_width = GetSize(sigA) + GetSize(sigB); int actual_mul_width = GetSize(sigH); - int actual_acc_width = GetSize(sigO); + int actual_acc_width = GetSize(sigCD); if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width)) reject; @@ -147,6 +148,7 @@ code addAB sigCD sigO reject; sigO = port(addAB, \Y); + sigCD.extend_u0(32, CD_SIGNED); } endcode @@ -255,7 +257,7 @@ code clock clock_pol sigO sigCD else if (muxB) sigCD = port(muxAB, \A); else log_abort(); - sigCD.extend_u0(32, addAB && param(addAB, \A_SIGNED).as_bool() && param(addAB, \B_SIGNED).as_bool()); + sigCD.extend_u0(32, addAB && param(addAB, \A_SIGNED).as_bool() && param(addAB, \B_SIGNED).as_bool()); } } endcode -- cgit v1.2.3 From 0b5b56c1ecab78d126bbab13598c184f5e28cccc Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 9 Aug 2019 15:19:33 -0700 Subject: Pack partial-product adder DSP48E1 packing --- passes/pmgen/xilinx_dsp.cc | 22 +++++++++++---- passes/pmgen/xilinx_dsp.pmg | 67 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 79 insertions(+), 10 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 389f0cb56..cd88f9449 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -37,16 +37,26 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) log("ffA: %s\n", log_id(st.ffA, "--")); log("ffB: %s\n", log_id(st.ffB, "--")); log("dsp: %s\n", log_id(st.dsp, "--")); + log("addAB: %s\n", log_id(st.addAB, "--")); log("ffP: %s\n", log_id(st.ffP, "--")); //log("muxP: %s\n", log_id(st.muxP, "--")); log("sigPused: %s\n", log_signal(st.sigPused)); - log_module(pm.module); #endif - log("Analysing %s.%s for Xilinx DSP register packing.\n", log_id(pm.module), log_id(st.dsp)); + log("Analysing %s.%s for Xilinx DSP packing.\n", log_id(pm.module), log_id(st.dsp)); Cell *cell = st.dsp; - log_assert(cell); + SigSpec P = st.sigP; + + if (st.addAB) { + log(" adder %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); + cell->setPort("\\C", st.sigC.extend_u0(48, true)); + SigSpec &opmode = cell->connections_.at("\\OPMODE"); + opmode[6] = State::S0; + opmode[5] = State::S1; + opmode[4] = State::S1; + pm.autoremove(st.addAB); + } if (st.clock != SigBit()) { @@ -79,7 +89,6 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) else log_abort(); } if (st.ffP) { - SigSpec P = cell->getPort("\\P"); SigSpec D; //if (st.muxP) // D = st.muxP->getPort("\\B"); @@ -87,7 +96,6 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) D = st.ffP->getPort("\\D"); SigSpec Q = st.ffP->getPort("\\Q"); P.replace(pm.sigmap(D), Q); - cell->setPort("\\P", P); cell->setParam("\\PREG", State::S1); if (st.ffP->type == "$dff") cell->setPort("\\CEP", State::S1); @@ -112,6 +120,10 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) log("\n"); } + if (GetSize(P) < 48) + P.append(pm.module->addWire(NEW_ID, 48-GetSize(P))); + cell->setPort("\\P", P); + pm.blacklist(cell); } diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index f95de9410..4f5fae8df 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,7 +1,8 @@ pattern xilinx_dsp state clock -state sigPused +state sigC sigP sigPused +state addAB match dsp select dsp->type.in(\DSP48E1) @@ -43,13 +44,69 @@ code clock } endcode +code sigP + sigP = port(dsp, \P); +endcode + +match addA + select addA->type.in($add) + select param(addA, \A_SIGNED).as_bool() && param(addA, \B_SIGNED).as_bool() + select nusers(port(addA, \A)) == 2 + //index port(addA, \A) === sigP.extract(0, param(addA, \A_WIDTH).as_int()) + filter GetSize(sigP) >= param(addA, \A_WIDTH).as_int() + filter port(addA, \A) == sigP.extract(0, param(addA, \A_WIDTH).as_int()) + optional +endmatch + +match addB + if !addA + select addB->type.in($add, $sub) + select param(addB, \A_SIGNED).as_bool() && param(addB, \B_SIGNED).as_bool() + select nusers(port(addB, \B)) == 2 + //index port(addB, \B) === sigP.extract(0, param(addB, \B_WIDTH).as_int()) + filter GetSize(sigP) >= param(addB, \B_WIDTH).as_int() + filter port(addB, \B) == sigP.extract(0, param(addB, \B_WIDTH).as_int()) + optional +endmatch + +code addAB sigC sigP + bool C_SIGNED = false; + if (addA) { + addAB = addA; + sigC = port(addAB, \B); + C_SIGNED = param(addAB, \B_SIGNED).as_bool(); + } + if (addB) { + addAB = addB; + sigC = port(addAB, \A); + C_SIGNED = param(addAB, \B_SIGNED).as_bool(); + } + if (addAB) { + // Ensure that adder is not used + SigSpec opmodeZ = port(dsp, \OPMODE).extract(4,3); + if (!opmodeZ.is_fully_zero()) + reject; + + int natural_mul_width = GetSize(port(dsp, \A)) + GetSize(port(dsp, \B)); + int actual_mul_width = GetSize(sigP); + int actual_acc_width = GetSize(sigC); + + if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width)) + reject; + //if ((actual_acc_width != actual_mul_width) && (param(dsp, \A_SIGNED).as_bool() != param(addAB, \A_SIGNED).as_bool())) + // reject; + + sigP = port(addAB, \Y); + sigC.extend_u0(32, C_SIGNED); + } +endcode + // Extract the bits of P that actually have a consumer // (as opposed to being a dummy) code sigPused - SigSpec P = port(dsp, \P); - for (int i = 0; i < GetSize(P); i++) - if (P[i].wire && nusers(P[i]) > 1) - sigPused.append(P[i]); + for (int i = 0; i < GetSize(sigP); i++) + if (sigP[i].wire && nusers(sigP[i]) > 1) + sigPused.append(sigP[i]); endcode match ffP -- cgit v1.2.3 From e83f231927c41e1771da2e8d1a2153361afc30b0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 9 Aug 2019 15:47:40 -0700 Subject: Cleanup --- passes/pmgen/ice40_dsp.pmg | 16 ++++++++-------- passes/pmgen/xilinx_dsp.pmg | 20 ++++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 41f34b4bd..a1b0b5004 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -21,8 +21,8 @@ code sigH endcode match ffA + if mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool() select ffA->type.in($dff) - filter mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool() filter !port(mul, \A).remove_const().empty() filter includes(port(ffA, \Q).to_sigbit_set(), port(mul, \A).remove_const().to_sigbit_set()) optional @@ -44,8 +44,8 @@ code sigA clock clock_pol endcode match ffB + if mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool() select ffB->type.in($dff) - filter mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool() filter !port(mul, \B).remove_const().empty() filter includes(port(ffB, \Q).to_sigbit_set(), port(mul, \B).remove_const().to_sigbit_set()) optional @@ -73,11 +73,11 @@ code sigB clock clock_pol endcode match ffH + if mul->type != \SB_MAC16 || (!param(mul, \TOP_8x8_MULT_REG).as_bool() && !param(mul, \BOT_8x8_MULT_REG).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG2).as_bool()) select ffH->type.in($dff) select nusers(port(ffH, \D)) == 2 index port(ffH, \D) === sigH // Ensure pipeline register is not already used - filter mul->type != \SB_MAC16 || (!param(mul, \TOP_8x8_MULT_REG).as_bool() && !param(mul, \BOT_8x8_MULT_REG).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG2).as_bool()) optional endmatch @@ -154,7 +154,7 @@ endcode match muxA select muxA->type.in($mux) - select nusers(port(muxA, \A)) == 2 + index nusers(port(muxA, \A)) === 2 index port(muxA, \A) === sigO optional endmatch @@ -162,7 +162,7 @@ endmatch match muxB if !muxA select muxB->type.in($mux) - select nusers(port(muxB, \B)) == 2 + index nusers(port(muxB, \B)) === 2 index port(muxB, \B) === sigO optional endmatch @@ -185,16 +185,16 @@ code sigOused endcode match ffO_lo + if nusers(sigOused.extract(0,std::min(16,GetSize(sigOused)))) == 2 select ffO_lo->type.in($dff) - filter nusers(sigOused.extract(0,std::min(16,param(ffO_lo, \WIDTH).as_int()))) == 2 filter includes(port(ffO_lo, \D).to_sigbit_set(), sigOused.extract(0,std::min(16,param(ffO_lo, \WIDTH).as_int())).remove_const().to_sigbit_set()) optional endmatch match ffO_hi + if GetSize(sigOused) > 16 + if nusers(sigOused.extract_end(16)) == 2 select ffO_hi->type.in($dff) - filter GetSize(sigOused) > 16 - filter nusers(sigOused.extract_end(16)) == 2 filter includes(port(ffO_hi, \D).to_sigbit_set(), sigOused.extract_end(16).remove_const().to_sigbit_set()) optional endmatch diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 4f5fae8df..f982a10cf 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -9,11 +9,11 @@ match dsp endmatch match ffA + if param(dsp, \AREG).as_int() == 0 + if !port(dsp, \A).remove_const().empty() select ffA->type.in($dff) // DSP48E1 does not support clock inversion select param(ffA, \CLK_POLARITY).as_bool() - filter param(dsp, \AREG).as_int() == 0 - filter !port(dsp, \A).remove_const().empty() filter includes(port(ffA, \Q).to_sigbit_set(), port(dsp, \A).remove_const().to_sigbit_set()) optional endmatch @@ -24,11 +24,11 @@ code clock endcode match ffB + if param(dsp, \BREG).as_int() == 0 + if !port(dsp, \B).remove_const().empty() select ffB->type.in($dff) // DSP48E1 does not support clock inversion select param(ffB, \CLK_POLARITY).as_bool() - filter param(dsp, \BREG).as_int() == 0 - filter !port(dsp, \B).remove_const().empty() filter includes(port(ffB, \Q).to_sigbit_set(), port(dsp, \B).remove_const().to_sigbit_set()) optional endmatch @@ -51,9 +51,9 @@ endcode match addA select addA->type.in($add) select param(addA, \A_SIGNED).as_bool() && param(addA, \B_SIGNED).as_bool() - select nusers(port(addA, \A)) == 2 + index nusers(port(addA, \A)) === 2 //index port(addA, \A) === sigP.extract(0, param(addA, \A_WIDTH).as_int()) - filter GetSize(sigP) >= param(addA, \A_WIDTH).as_int() + filter param(addA, \A_WIDTH).as_int() <= GetSize(sigP) filter port(addA, \A) == sigP.extract(0, param(addA, \A_WIDTH).as_int()) optional endmatch @@ -62,9 +62,9 @@ match addB if !addA select addB->type.in($add, $sub) select param(addB, \A_SIGNED).as_bool() && param(addB, \B_SIGNED).as_bool() - select nusers(port(addB, \B)) == 2 + index nusers(port(addB, \B)) === 2 //index port(addB, \B) === sigP.extract(0, param(addB, \B_WIDTH).as_int()) - filter GetSize(sigP) >= param(addB, \B_WIDTH).as_int() + filter param(addB, \B_WIDTH).as_int() <= GetSize(sigP) filter port(addB, \B) == sigP.extract(0, param(addB, \B_WIDTH).as_int()) optional endmatch @@ -110,12 +110,12 @@ code sigPused endcode match ffP + if param(dsp, \PREG).as_int() == 0 if !sigPused.empty() select ffP->type.in($dff) - select nusers(port(ffP, \D)) == 2 + index nusers(port(ffP, \D)) === 2 // DSP48E1 does not support clock inversion select param(ffP, \CLK_POLARITY).as_bool() - filter param(dsp, \PREG).as_int() == 0 filter param(ffP, \WIDTH).as_int() >= GetSize(sigPused) filter includes(port(ffP, \D).to_sigbit_set(), sigPused.to_sigbit_set()) optional -- cgit v1.2.3 From dfc878deb4caadbb058588b2b70b374b37978b27 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 9 Aug 2019 16:23:32 -0700 Subject: Another filter -> if --- passes/pmgen/ice40_dsp.pmg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index a1b0b5004..e0a213e85 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -22,8 +22,8 @@ endcode match ffA if mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool() + if !port(mul, \A).remove_const().empty() select ffA->type.in($dff) - filter !port(mul, \A).remove_const().empty() filter includes(port(ffA, \Q).to_sigbit_set(), port(mul, \A).remove_const().to_sigbit_set()) optional endmatch @@ -45,8 +45,8 @@ endcode match ffB if mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool() + if !port(mul, \B).remove_const().empty() select ffB->type.in($dff) - filter !port(mul, \B).remove_const().empty() filter includes(port(ffB, \Q).to_sigbit_set(), port(mul, \B).remove_const().to_sigbit_set()) optional endmatch -- cgit v1.2.3 From 3dd3ab98c2bb83f644fb1962d4de27a7416b0113 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 9 Aug 2019 17:23:12 -0700 Subject: Improve ice40_dsp for non-fully-32-bit adders --- passes/pmgen/ice40_dsp.pmg | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index e0a213e85..c59c5d20a 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -106,7 +106,9 @@ endcode match addA select addA->type.in($add) select nusers(port(addA, \A)) == 2 - index port(addA, \A) === sigH + filter param(addA, \A_WIDTH).as_int() <= GetSize(sigH) + //index port(addA, \A) === sigH.extract(0, param(addA, \A_WIDTH).as_int()) + filter port(addA, \A) == sigH.extract(0, param(addA, \A_WIDTH).as_int()) optional endmatch @@ -114,7 +116,9 @@ match addB if !addA select addB->type.in($add, $sub) select nusers(port(addB, \B)) == 2 - index port(addB, \B) === sigH + filter param(addB, \B_WIDTH).as_int() <= GetSize(sigH) + //index port(addB, \B) === sigH.extract(0, param(addB, \B_WIDTH).as_int()) + filter port(addB, \B) == sigH.extract(0, param(addB, \B_WIDTH).as_int()) optional endmatch @@ -144,7 +148,8 @@ code addAB sigCD sigO if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width)) reject; - if ((actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(addAB, \A_SIGNED).as_bool())) + // If accumulator, check adder width and signedness + if (sigCD == sigH && (actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(addAB, \A_SIGNED).as_bool())) reject; sigO = port(addAB, \Y); -- cgit v1.2.3 From ab1d63a56595f11e10a5326bd83ce84d08badabe Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 9 Aug 2019 17:35:13 -0700 Subject: Check nusers of DSP output, not whole flop --- passes/pmgen/xilinx_dsp.pmg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index f982a10cf..5dee36a11 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -112,8 +112,8 @@ endcode match ffP if param(dsp, \PREG).as_int() == 0 if !sigPused.empty() + if nusers(sigPused) == 2 select ffP->type.in($dff) - index nusers(port(ffP, \D)) === 2 // DSP48E1 does not support clock inversion select param(ffP, \CLK_POLARITY).as_bool() filter param(ffP, \WIDTH).as_int() >= GetSize(sigPused) -- cgit v1.2.3 From 0597a3ea238ee100607271fb25a2d09fbd128bf0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 13 Aug 2019 10:23:07 -0700 Subject: Rename to XilinxDspPass --- passes/pmgen/xilinx_dsp.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index cd88f9449..31c0d48c5 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -127,8 +127,8 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) pm.blacklist(cell); } -struct Ice40DspPass : public Pass { - Ice40DspPass() : Pass("xilinx_dsp", "Xilinx: pack DSP registers") { } +struct XilinxDspPass : public Pass { + XilinxDspPass() : Pass("xilinx_dsp", "Xilinx: pack DSP registers") { } void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -156,6 +156,6 @@ struct Ice40DspPass : public Pass { for (auto module : design->selected_modules()) xilinx_dsp_pm(module, module->selected_cells()).run_xilinx_dsp(pack_xilinx_dsp); } -} Ice40DspPass; +} XilinxDspPass; PRIVATE_NAMESPACE_END -- cgit v1.2.3 From 1b0e68db945ee8a62a445cf41668844812c436eb Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 13 Aug 2019 17:09:28 -0700 Subject: Revert changes to RTLIL::SigSpec methods --- passes/pmgen/ice40_dsp.cc | 3 ++- passes/pmgen/ice40_dsp.pmg | 34 ++++++++++++++++++++++++++++------ 2 files changed, 30 insertions(+), 7 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index bb45b8a4e..66f70399d 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -23,9 +23,10 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -template bool includes(const T &lhs, const T &rhs) { +template inline bool includes(const T &lhs, const T &rhs) { return std::includes(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } +#include #include "passes/pmgen/ice40_dsp_pm.h" void create_ice40_dsp(ice40_dsp_pm &pm) diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index c59c5d20a..cda7535f3 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -2,6 +2,7 @@ pattern ice40_dsp state clock state clock_pol +state > sigAset sigBset state sigA sigB sigCD sigH sigO sigOused state addAB muxAB @@ -10,6 +11,15 @@ match mul select GetSize(mul->getPort(\A)) + GetSize(mul->getPort(\B)) > 10 endmatch +code sigAset sigBset + SigSpec A = port(mul, \A); + A.remove_const(); + sigAset = A.to_sigbit_set(); + SigSpec B = port(mul, \B); + B.remove_const(); + sigBset = B.to_sigbit_set(); +endcode + code sigH if (mul->type == $mul) sigH = mul->getPort(\Y); @@ -22,9 +32,9 @@ endcode match ffA if mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool() - if !port(mul, \A).remove_const().empty() + if !sigAset.empty() select ffA->type.in($dff) - filter includes(port(ffA, \Q).to_sigbit_set(), port(mul, \A).remove_const().to_sigbit_set()) + filter includes(port(ffA, \Q).to_sigbit_set(), sigAset) optional endmatch @@ -45,9 +55,9 @@ endcode match ffB if mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool() - if !port(mul, \B).remove_const().empty() + if !sigBset.empty() select ffB->type.in($dff) - filter includes(port(ffB, \Q).to_sigbit_set(), port(mul, \B).remove_const().to_sigbit_set()) + filter includes(port(ffB, \Q).to_sigbit_set(), sigBset) optional endmatch @@ -192,18 +202,30 @@ endcode match ffO_lo if nusers(sigOused.extract(0,std::min(16,GetSize(sigOused)))) == 2 select ffO_lo->type.in($dff) - filter includes(port(ffO_lo, \D).to_sigbit_set(), sigOused.extract(0,std::min(16,param(ffO_lo, \WIDTH).as_int())).remove_const().to_sigbit_set()) optional endmatch +code + SigSpec O = sigOused.extract(0,std::min(16,param(ffO_lo, \WIDTH).as_int())); + O.remove_const(); + if (!includes(port(ffO_lo, \D).to_sigbit_set(), O.to_sigbit_set())) + reject; +endcode + match ffO_hi if GetSize(sigOused) > 16 if nusers(sigOused.extract_end(16)) == 2 select ffO_hi->type.in($dff) - filter includes(port(ffO_hi, \D).to_sigbit_set(), sigOused.extract_end(16).remove_const().to_sigbit_set()) optional endmatch +code + SigSpec O = sigOused.extract_end(16); + O.remove_const(); + if (!includes(port(ffO_hi, \D).to_sigbit_set(), O.to_sigbit_set())) + reject; +endcode + code clock clock_pol sigO sigCD if (ffO_lo || ffO_hi) { if (mul->type == \SB_MAC16) { -- cgit v1.2.3 From 2f04beeeb5114058ce762d0393859d517a9a35eb Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 13 Aug 2019 17:11:35 -0700 Subject: Perform C -> PCIN optimisation after pattern matcher --- passes/pmgen/xilinx_dsp.cc | 67 ++++++++++++++++++++++++++++++++++++++------- passes/pmgen/xilinx_dsp.pmg | 24 ++++++++++------ 2 files changed, 72 insertions(+), 19 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 31c0d48c5..e7b72e312 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -23,22 +23,23 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -template bool includes(const T &lhs, const T &rhs) { +template inline bool includes(const T &lhs, const T &rhs) { return std::includes(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } +#include #include "passes/pmgen/xilinx_dsp_pm.h" -void pack_xilinx_dsp(xilinx_dsp_pm &pm) +void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) { auto &st = pm.st_xilinx_dsp; #if 1 log("\n"); - log("ffA: %s\n", log_id(st.ffA, "--")); - log("ffB: %s\n", log_id(st.ffB, "--")); - log("dsp: %s\n", log_id(st.dsp, "--")); - log("addAB: %s\n", log_id(st.addAB, "--")); - log("ffP: %s\n", log_id(st.ffP, "--")); + log("ffA: %s\n", log_id(st.ffA, "--")); + log("ffB: %s\n", log_id(st.ffB, "--")); + log("dsp: %s\n", log_id(st.dsp, "--")); + log("addAB: %s\n", log_id(st.addAB, "--")); + log("ffP: %s\n", log_id(st.ffP, "--")); //log("muxP: %s\n", log_id(st.muxP, "--")); log("sigPused: %s\n", log_signal(st.sigPused)); #endif @@ -46,11 +47,17 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) log("Analysing %s.%s for Xilinx DSP packing.\n", log_id(pm.module), log_id(st.dsp)); Cell *cell = st.dsp; + bit_to_driver.insert(std::make_pair(cell->getPort("\\P")[17], cell)); SigSpec P = st.sigP; if (st.addAB) { + log_assert(st.addAB->getParam("\\A_SIGNED").as_bool()); + log_assert(st.addAB->getParam("\\B_SIGNED").as_bool()); log(" adder %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); - cell->setPort("\\C", st.sigC.extend_u0(48, true)); + + SigSpec C = st.sigC; + C.extend_u0(48, true); + cell->setPort("\\C", C); SigSpec &opmode = cell->connections_.at("\\OPMODE"); opmode[6] = State::S0; opmode[5] = State::S1; @@ -153,8 +160,48 @@ struct XilinxDspPass : public Pass { } extra_args(args, argidx, design); - for (auto module : design->selected_modules()) - xilinx_dsp_pm(module, module->selected_cells()).run_xilinx_dsp(pack_xilinx_dsp); + for (auto module : design->selected_modules()) { + xilinx_dsp_pm pm(module, module->selected_cells()); + dict bit_to_driver; + auto f = [&bit_to_driver](xilinx_dsp_pm &pm){ pack_xilinx_dsp(bit_to_driver, pm); }; + pm.run_xilinx_dsp(f); + + // Look for ability to convert C input from another DSP into PCIN + // NB: Needs to be done after pattern matcher has folded all + // $add cells into the DSP + for (auto cell : module->cells()) { + if (cell->type != "\\DSP48E1") + continue; + SigSpec &opmode = cell->connections_.at("\\OPMODE"); + if (opmode.extract(4,3) != Const::from_string("011")) + continue; + SigSpec C = pm.sigmap(cell->getPort("\\C")); + if (C.has_const()) + continue; + auto it = bit_to_driver.find(C[0]); + if (it == bit_to_driver.end()) + continue; + auto driver = it->second; + + // Unextend C + int i; + for (i = GetSize(C)-1; i > 0; i--) + if (C[i] != C[i-1]) + break; + if (i > 48-17) + continue; + if (driver->getPort("\\P").extract(17, i) == C.extract(0, i)) { + cell->setPort("\\C", Const(0, 48)); + Wire *cascade = module->addWire(NEW_ID, 48); + driver->setPort("\\PCOUT", cascade); + cell->setPort("\\PCIN", cascade); + opmode[6] = State::S1; + opmode[5] = State::S0; + opmode[4] = State::S1; + bit_to_driver.erase(it); + } + } + } } } XilinxDspPass; diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 5dee36a11..1a3dcdcbb 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,6 +1,7 @@ pattern xilinx_dsp state clock +state > sigAset sigBset state sigC sigP sigPused state addAB @@ -8,13 +9,22 @@ match dsp select dsp->type.in(\DSP48E1) endmatch +code sigAset sigBset + SigSpec A = port(dsp, \A); + A.remove_const(); + sigAset = A.to_sigbit_set(); + SigSpec B = port(dsp, \B); + B.remove_const(); + sigBset = B.to_sigbit_set(); +endcode + match ffA if param(dsp, \AREG).as_int() == 0 - if !port(dsp, \A).remove_const().empty() + if !sigAset.empty() select ffA->type.in($dff) // DSP48E1 does not support clock inversion select param(ffA, \CLK_POLARITY).as_bool() - filter includes(port(ffA, \Q).to_sigbit_set(), port(dsp, \A).remove_const().to_sigbit_set()) + filter includes(port(ffA, \Q).to_sigbit_set(), sigAset) optional endmatch @@ -25,11 +35,11 @@ endcode match ffB if param(dsp, \BREG).as_int() == 0 - if !port(dsp, \B).remove_const().empty() + if !sigBset.empty() select ffB->type.in($dff) // DSP48E1 does not support clock inversion select param(ffB, \CLK_POLARITY).as_bool() - filter includes(port(ffB, \Q).to_sigbit_set(), port(dsp, \B).remove_const().to_sigbit_set()) + filter includes(port(ffB, \Q).to_sigbit_set(), sigBset) optional endmatch @@ -65,21 +75,18 @@ match addB index nusers(port(addB, \B)) === 2 //index port(addB, \B) === sigP.extract(0, param(addB, \B_WIDTH).as_int()) filter param(addB, \B_WIDTH).as_int() <= GetSize(sigP) - filter port(addB, \B) == sigP.extract(0, param(addB, \B_WIDTH).as_int()) + filter port(addB, \B) == sigP.extract(0, param(addB, \B_WIDTH).as_int()) optional endmatch code addAB sigC sigP - bool C_SIGNED = false; if (addA) { addAB = addA; sigC = port(addAB, \B); - C_SIGNED = param(addAB, \B_SIGNED).as_bool(); } if (addB) { addAB = addB; sigC = port(addAB, \A); - C_SIGNED = param(addAB, \B_SIGNED).as_bool(); } if (addAB) { // Ensure that adder is not used @@ -97,7 +104,6 @@ code addAB sigC sigP // reject; sigP = port(addAB, \Y); - sigC.extend_u0(32, C_SIGNED); } endcode -- cgit v1.2.3 From aad97168b070509b7bd479ed3b9956452a28e3ec Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 14 Aug 2019 10:22:33 -0700 Subject: Fixes for reverting SigSpec helper functions --- passes/pmgen/ice40_dsp.cc | 4 ++-- passes/pmgen/ice40_dsp.pmg | 20 ++++++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 66f70399d..6f0539679 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -155,9 +155,9 @@ void create_ice40_dsp(ice40_dsp_pm &pm) // If we have a signed multiply-add, then perform sign extension // TODO: Need to check CD[31:16] is sign extension of CD[15:0]? if (st.addAB->getParam("\\A_SIGNED").as_bool() && st.addAB->getParam("\\B_SIGNED").as_bool()) - pm.module->connect(O[-1], O[-2]); + pm.module->connect(O[32], O[31]); else - cell->setPort("\\CO", O[-1]); + cell->setPort("\\CO", O[32]); O.remove(O_width-1); } else diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index cda7535f3..d64c8a391 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -206,10 +206,12 @@ match ffO_lo endmatch code - SigSpec O = sigOused.extract(0,std::min(16,param(ffO_lo, \WIDTH).as_int())); - O.remove_const(); - if (!includes(port(ffO_lo, \D).to_sigbit_set(), O.to_sigbit_set())) - reject; + if (ffO_lo) { + SigSpec O = sigOused.extract(0,std::min(16,param(ffO_lo, \WIDTH).as_int())); + O.remove_const(); + if (!includes(port(ffO_lo, \D).to_sigbit_set(), O.to_sigbit_set())) + reject; + } endcode match ffO_hi @@ -220,10 +222,12 @@ match ffO_hi endmatch code - SigSpec O = sigOused.extract_end(16); - O.remove_const(); - if (!includes(port(ffO_hi, \D).to_sigbit_set(), O.to_sigbit_set())) - reject; + if (ffO_hi) { + SigSpec O = sigOused.extract_end(16); + O.remove_const(); + if (!includes(port(ffO_hi, \D).to_sigbit_set(), O.to_sigbit_set())) + reject; + } endcode code clock clock_pol sigO sigCD -- cgit v1.2.3 From 27d5df9467fb425234a466d0d63b8a94e37ca596 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 15 Aug 2019 12:19:34 -0700 Subject: ffH -> ffFJKG --- passes/pmgen/ice40_dsp.cc | 14 +++++++------- passes/pmgen/ice40_dsp.pmg | 16 ++++++++-------- 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 6f0539679..a1a397b83 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -38,7 +38,7 @@ void create_ice40_dsp(ice40_dsp_pm &pm) log("ffA: %s\n", log_id(st.ffA, "--")); log("ffB: %s\n", log_id(st.ffB, "--")); log("mul: %s\n", log_id(st.mul, "--")); - log("ffH: %s\n", log_id(st.ffH, "--")); + log("ffFJKG: %s\n", log_id(st.ffFJKG, "--")); log("addAB: %s\n", log_id(st.addAB, "--")); log("muxAB: %s\n", log_id(st.muxAB, "--")); log("ffO_lo: %s\n", log_id(st.ffO_lo, "--")); @@ -119,8 +119,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm) if (st.ffB) log(" ffB:%s", log_id(st.ffB)); - if (st.ffH) - log(" ffH:%s", log_id(st.ffH)); + if (st.ffFJKG) + log(" ffFJKG:%s", log_id(st.ffFJKG)); if (st.ffO_lo) log(" ffO_lo:%s", log_id(st.ffO_lo)); @@ -206,9 +206,9 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam("\\C_REG", State::S0); cell->setParam("\\D_REG", State::S0); - cell->setParam("\\TOP_8x8_MULT_REG", st.ffH ? State::S1 : State::S0); - cell->setParam("\\BOT_8x8_MULT_REG", st.ffH ? State::S1 : State::S0); - cell->setParam("\\PIPELINE_16x16_MULT_REG1", st.ffH ? State::S1 : State::S0); + cell->setParam("\\TOP_8x8_MULT_REG", st.ffFJKG ? State::S1 : State::S0); + cell->setParam("\\BOT_8x8_MULT_REG", st.ffFJKG ? State::S1 : State::S0); + cell->setParam("\\PIPELINE_16x16_MULT_REG1", st.ffFJKG ? State::S1 : State::S0); cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0); cell->setParam("\\TOPOUTPUT_SELECT", Const(st.ffO_hi ? 1 : (st.addAB ? 0 : 3), 2)); @@ -229,7 +229,7 @@ void create_ice40_dsp(ice40_dsp_pm &pm) pm.autoremove(st.mul); else pm.blacklist(st.mul); - pm.autoremove(st.ffH); + pm.autoremove(st.ffFJKG); pm.autoremove(st.addAB); if (st.ffO_lo) { SigSpec O = st.sigO.extract(0,std::min(16,st.ffO_lo->getParam("\\WIDTH").as_int())); diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index d64c8a391..11064e072 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -82,11 +82,11 @@ code sigB clock clock_pol } endcode -match ffH +match ffFJKG if mul->type != \SB_MAC16 || (!param(mul, \TOP_8x8_MULT_REG).as_bool() && !param(mul, \BOT_8x8_MULT_REG).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG2).as_bool()) - select ffH->type.in($dff) - select nusers(port(ffH, \D)) == 2 - index port(ffH, \D) === sigH + select ffFJKG->type.in($dff) + select nusers(port(ffFJKG, \D)) == 2 + index port(ffFJKG, \D) === sigH // Ensure pipeline register is not already used optional endmatch @@ -94,16 +94,16 @@ endmatch code sigH sigO clock clock_pol sigO = sigH; - if (ffH) { - sigH = port(ffH, \Q); + if (ffFJKG) { + sigH = port(ffFJKG, \Q); for (auto b : sigH) if (b.wire->get_bool_attribute(\keep)) reject; sigO = sigH; - SigBit c = port(ffH, \CLK).as_bit(); - bool cp = param(ffH, \CLK_POLARITY).as_bool(); + SigBit c = port(ffFJKG, \CLK).as_bit(); + bool cp = param(ffFJKG, \CLK_POLARITY).as_bool(); if (clock != SigBit() && (c != clock || cp != clock_pol)) reject; -- cgit v1.2.3 From 96ee7b9cf7a6a9010bc820dc110bf945c35cb32e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 15 Aug 2019 12:30:46 -0700 Subject: Simplify --- passes/pmgen/ice40_dsp.pmg | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 11064e072..b387ca0a2 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -92,16 +92,12 @@ match ffFJKG endmatch code sigH sigO clock clock_pol - sigO = sigH; - if (ffFJKG) { sigH = port(ffFJKG, \Q); for (auto b : sigH) if (b.wire->get_bool_attribute(\keep)) reject; - sigO = sigH; - SigBit c = port(ffFJKG, \CLK).as_bit(); bool cp = param(ffFJKG, \CLK_POLARITY).as_bool(); @@ -111,6 +107,8 @@ code sigH sigO clock clock_pol clock = c; clock_pol = cp; } + + sigO = sigH; endcode match addA -- cgit v1.2.3 From c320abc3f490b09b21804581c2b386c30d186a1e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 15 Aug 2019 12:34:11 -0700 Subject: xilinx_dsp to be sensitive to keep attribute --- passes/pmgen/xilinx_dsp.pmg | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 1a3dcdcbb..7f1958d5d 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -29,8 +29,13 @@ match ffA endmatch code clock - if (ffA) + if (ffA) { clock = port(ffA, \CLK).as_bit(); + + for (auto b : port(ffA, \Q)) + if (b.wire->get_bool_attribute(\keep)) + reject; + } endcode match ffB @@ -45,6 +50,10 @@ endmatch code clock if (ffB) { + for (auto b : port(ffB, \Q)) + if (b.wire->get_bool_attribute(\keep)) + reject; + SigBit c = port(ffB, \CLK).as_bit(); if (clock != SigBit() && c != clock) @@ -156,6 +165,10 @@ code ffP clock // ffP = ffY; if (ffP) { + for (auto b : port(ffP, \Q)) + if (b.wire->get_bool_attribute(\keep)) + reject; + SigBit c = port(ffP, \CLK).as_bit(); if (clock != SigBit() && c != clock) -- cgit v1.2.3 From 9bfe924e17a87fac8a35fcb7ff5e067f6c520e07 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 19 Aug 2019 09:40:01 -0700 Subject: Set abc_flop and use it in toposort --- passes/techmap/abc9.cc | 82 +++++++++++++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 31 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 50a6e0fe5..df62b4fa5 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -443,6 +443,8 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri design->remove(design->module(ID($__abc9__))); #endif + design->selection_stack.pop_back(); + // Now 'unexpose' those wires by undoing // the expose operation -- remove them from PO/PI // and re-connecting them back together @@ -568,19 +570,17 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri dict> bit2sinks; std::map cell_stats; - for (auto c : mapped_mod->cells()) + for (auto mapped_cell : mapped_mod->cells()) { - toposort.node(c->name); + toposort.node(mapped_cell->name); RTLIL::Cell *cell = nullptr; - if (c->type == ID($_NOT_)) { - RTLIL::SigBit a_bit = c->getPort(ID(A)); - RTLIL::SigBit y_bit = c->getPort(ID(Y)); - bit_users[a_bit].insert(c->name); - bit_drivers[y_bit].insert(c->name); + if (mapped_cell->type == ID($_NOT_)) { + RTLIL::SigBit a_bit = mapped_cell->getPort(ID(A)); + RTLIL::SigBit y_bit = mapped_cell->getPort(ID(Y)); if (!a_bit.wire) { - c->setPort(ID(Y), module->addWire(NEW_ID)); + mapped_cell->setPort(ID(Y), module->addWire(NEW_ID)); RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name)); log_assert(wire); module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1); @@ -604,38 +604,40 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri if (!driving_lut) { // If a driver couldn't be found (could be from PI or box CI) // then implement using a LUT - cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())), + cell = module->addLut(remap_name(stringf("%s$lut", mapped_cell->name.c_str())), RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset), RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset), RTLIL::Const::from_string("01")); bit2sinks[cell->getPort(ID(A))].push_back(cell); cell_stats[ID($lut)]++; + bit_users[a_bit].insert(mapped_cell->name); + bit_drivers[y_bit].insert(mapped_cell->name); } else - not2drivers[c] = driving_lut; + not2drivers[mapped_cell] = driving_lut; continue; } if (cell && markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; continue; } - cell_stats[c->type]++; + cell_stats[mapped_cell->type]++; RTLIL::Cell *existing_cell = nullptr; - if (c->type == ID($lut)) { - if (GetSize(c->getPort(ID(A))) == 1 && c->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) { - SigSpec my_a = module->wires_.at(remap_name(c->getPort(ID(A)).as_wire()->name)); - SigSpec my_y = module->wires_.at(remap_name(c->getPort(ID(Y)).as_wire()->name)); + if (mapped_cell->type == ID($lut)) { + if (GetSize(mapped_cell->getPort(ID(A))) == 1 && mapped_cell->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) { + SigSpec my_a = module->wires_.at(remap_name(mapped_cell->getPort(ID(A)).as_wire()->name)); + SigSpec my_y = module->wires_.at(remap_name(mapped_cell->getPort(ID(Y)).as_wire()->name)); module->connect(my_y, my_a); - if (markgroups) c->attributes[ID(abcgroup)] = map_autoidx; + if (markgroups) mapped_cell->attributes[ID(abcgroup)] = map_autoidx; log_abort(); continue; } - cell = module->addCell(remap_name(c->name), c->type); + cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); } else { - existing_cell = module->cell(c->name); + existing_cell = module->cell(mapped_cell->name); log_assert(existing_cell); - cell = module->addCell(remap_name(c->name), c->type); + cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); module->swap_names(cell, existing_cell); } @@ -652,10 +654,12 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri cell->parameters.erase(it); } else { - cell->parameters = c->parameters; - cell->attributes = c->attributes; + cell->parameters = mapped_cell->parameters; + cell->attributes = mapped_cell->attributes; } - for (auto &conn : c->connections()) { + + auto abc_flop = mapped_cell->attributes.count("\\abc_flop"); + for (auto &conn : mapped_cell->connections()) { RTLIL::SigSpec newsig; for (auto c : conn.second.chunks()) { if (c.width == 0) @@ -667,15 +671,17 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri } cell->setPort(conn.first, newsig); - if (cell->input(conn.first)) { - for (auto i : newsig) - bit2sinks[i].push_back(cell); - for (auto i : conn.second) - bit_users[i].insert(c->name); + if (!abc_flop) { + if (cell->input(conn.first)) { + for (auto i : newsig) + bit2sinks[i].push_back(cell); + for (auto i : conn.second) + bit_users[i].insert(mapped_cell->name); + } + if (cell->output(conn.first)) + for (auto i : conn.second) + bit_drivers[i].insert(mapped_cell->name); } - if (cell->output(conn.first)) - for (auto i : conn.second) - bit_drivers[i].insert(c->name); } } @@ -701,7 +707,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri } for (auto &it : cell_stats) - log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second); + log("ABC RESULTS: %15s cells: %8d\n", log_id(it.first), it.second); int in_wires = 0, out_wires = 0; // Stitch in mapped_mod's inputs/outputs into module @@ -734,7 +740,21 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri for (auto driver_cell : bit_drivers.at(it.first)) for (auto user_cell : it.second) toposort.edge(driver_cell, user_cell); +#if 0 + toposort.analyze_loops = true; +#endif bool no_loops = toposort.sort(); +#if 0 + unsigned i = 0; + for (auto &it : toposort.loops) { + log(" loop %d\n", i++); + for (auto cell_name : it) { + auto cell = mapped_mod->cell(cell_name); + log_assert(cell); + log("\t%s (%s @ %s)\n", log_id(cell), log_id(cell->type), cell->get_src_attribute().c_str()); + } + } +#endif log_assert(no_loops); for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) { -- cgit v1.2.3 From e301440a0bae76dcff159c77274c91aad40021c0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 19 Aug 2019 09:51:49 -0700 Subject: Use attributes instead of params --- passes/techmap/abc9.cc | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index df62b4fa5..d52be1836 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -646,12 +646,8 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri cell->parameters = existing_cell->parameters; cell->attributes = existing_cell->attributes; - auto it = cell->parameters.find("\\$abc_flop_clk_pol"); - if (it != cell->parameters.end()) - cell->parameters.erase(it); - it = cell->parameters.find("\\$abc_flop_en_pol"); - if (it != cell->parameters.end()) - cell->parameters.erase(it); + cell->attributes.erase("\\abc_flop_clk_pol"); + cell->attributes.erase("\\abc_flop_en_pol"); } else { cell->parameters = mapped_cell->parameters; @@ -1265,14 +1261,32 @@ struct Abc9Pass : public Pass { continue; } - auto jt = cell->parameters.find("\\$abc_flop_clk_pol"); + auto jt = cell->attributes.find("\\abc_flop_clk_pol"); if (jt == cell->parameters.end()) - log_error("'$abc_flop_clk_pol' parameter not found on module '%s'.\n", log_id(cell->type)); - bool this_clk_pol = jt->second.as_bool(); + log_error("'abc_flop_clk_pol' attribute not found on module '%s'.\n", log_id(cell->type)); + bool this_clk_pol; + if (jt->second.flags == RTLIL::ConstFlags::CONST_FLAG_STRING) { + auto param = jt->second.decode_string(); + auto kt = cell->parameters.find(param); + if (kt == cell->parameters.end()) + log_error("'abc_flop_clk_pol' value '%s' is not a parameter on module '%s'.\n", param.c_str(), log_id(cell->type)); + this_clk_pol = kt->second.as_bool(); + } + else + this_clk_pol = jt->second.as_bool(); jt = cell->parameters.find("\\$abc_flop_en_pol"); if (jt == cell->parameters.end()) - log_error("'$abc_flop_en_pol' parameter not found on module '%s'.\n", log_id(cell->type)); - bool this_en_pol = jt->second.as_bool(); + log_error("'abc_flop_en_pol' attribute not found on module '%s'.\n", log_id(cell->type)); + bool this_en_pol; + if (jt->second.flags == RTLIL::ConstFlags::CONST_FLAG_STRING) { + auto param = jt->second.decode_string(); + auto kt = cell->parameters.find(param); + if (kt == cell->parameters.end()) + log_error("'abc_flop_en_pol' value '%s' is not a parameter on module '%s'.\n", param.c_str(), log_id(cell->type)); + this_en_pol = kt->second.as_bool(); + } + else + this_en_pol = jt->second.as_bool(); const auto &data = it->second; key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(data.first)), this_en_pol, assign_map(cell->getPort(data.second))); -- cgit v1.2.3 From ba2261e21a18b969473f228b5f55bd5612558ed8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 19 Aug 2019 11:18:33 -0700 Subject: Move from cell attr to module attr --- passes/techmap/abc9.cc | 88 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 24 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 398df190c..be2a8d50b 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -1202,7 +1202,15 @@ struct Abc9Pass : public Pass { std::map> bit_to_cell, bit_to_cell_up, bit_to_cell_down; pool seen_cells; - dict> flop_data; + struct flop_data_t { + IdString clk_port; + IdString clk_pol_param; + bool clk_pol; + IdString en_port; + IdString en_pol_param; + bool en_pol; + }; + dict flop_data; for (auto cell : all_cells) { clkdomain_t key; @@ -1253,7 +1261,40 @@ struct Abc9Pass : public Pass { log_error("'abc_flop_clk' attribute not found on any ports on module '%s'.\n", log_id(cell->type)); if (abc_flop_en == IdString()) log_error("'abc_flop_en' attribute not found on any ports on module '%s'.\n", log_id(cell->type)); - it = flop_data.insert(std::make_pair(cell->type, std::make_pair(abc_flop_clk, abc_flop_en))).first; + + auto jt = inst_module->attributes.find("\\abc_flop_clk_pol"); + if (jt == inst_module->attributes.end()) + log_error("'abc_flop_clk_pol' attribute not found on module '%s'.\n", log_id(inst_module)); + IdString abc_flop_clk_pol_param; + bool abc_flop_clk_pol; + if (jt->second.flags == RTLIL::ConstFlags::CONST_FLAG_STRING) { + auto param = jt->second.decode_string(); + abc_flop_clk_pol = (param[0] == '!'); + if (abc_flop_clk_pol) + abc_flop_clk_pol_param = RTLIL::escape_id(param.substr(1)); + else + abc_flop_clk_pol_param = RTLIL::escape_id(param); + } + else + abc_flop_clk_pol = !jt->second.as_bool(); + jt = inst_module->attributes.find("\\abc_flop_en_pol"); + if (jt == inst_module->attributes.end()) + log_error("'abc_flop_en_pol' attribute not found on module '%s'.\n", log_id(inst_module)); + IdString abc_flop_en_pol_param; + bool abc_flop_en_pol; + if (jt->second.flags == RTLIL::ConstFlags::CONST_FLAG_STRING) { + auto param = jt->second.decode_string(); + abc_flop_en_pol = (param[0] == '!'); + if (abc_flop_en_pol) + abc_flop_en_pol_param = RTLIL::escape_id(param.substr(1)); + else + abc_flop_en_pol_param = RTLIL::escape_id(param); + } + else + abc_flop_en_pol = !jt->second.as_bool(); + + it = flop_data.insert(std::make_pair(cell->type, flop_data_t{abc_flop_clk, abc_flop_clk_pol_param, abc_flop_clk_pol, + abc_flop_en, abc_flop_en_pol_param, abc_flop_en_pol})).first; } else { it = flop_data.find(cell->type); @@ -1261,35 +1302,34 @@ struct Abc9Pass : public Pass { continue; } - auto jt = cell->attributes.find("\\abc_flop_clk_pol"); - if (jt == cell->parameters.end()) - log_error("'abc_flop_clk_pol' attribute not found on module '%s'.\n", log_id(cell->type)); + const auto &data = it->second; + bool this_clk_pol; - if (jt->second.flags == RTLIL::ConstFlags::CONST_FLAG_STRING) { - auto param = jt->second.decode_string(); - auto kt = cell->parameters.find(param); - if (kt == cell->parameters.end()) + if (data.clk_pol_param == IdString()) + this_clk_pol = data.clk_pol; + else { + auto param = data.clk_pol_param; + auto jt = cell->parameters.find(param); + if (jt == cell->parameters.end()) log_error("'abc_flop_clk_pol' value '%s' is not a parameter on module '%s'.\n", param.c_str(), log_id(cell->type)); - this_clk_pol = kt->second.as_bool(); - } - else this_clk_pol = jt->second.as_bool(); - jt = cell->parameters.find("\\$abc_flop_en_pol"); - if (jt == cell->parameters.end()) - log_error("'abc_flop_en_pol' attribute not found on module '%s'.\n", log_id(cell->type)); + if (data.clk_pol) + this_clk_pol = !this_clk_pol; + } bool this_en_pol; - if (jt->second.flags == RTLIL::ConstFlags::CONST_FLAG_STRING) { - auto param = jt->second.decode_string(); - auto kt = cell->parameters.find(param); - if (kt == cell->parameters.end()) + if (data.en_pol_param == IdString()) + this_en_pol = data.en_pol; + else { + auto param = data.en_pol_param; + auto jt = cell->parameters.find(param); + if (jt == cell->parameters.end()) log_error("'abc_flop_en_pol' value '%s' is not a parameter on module '%s'.\n", param.c_str(), log_id(cell->type)); - this_en_pol = kt->second.as_bool(); - } - else this_en_pol = jt->second.as_bool(); + if (data.en_pol) + this_en_pol = !this_en_pol; + } - const auto &data = it->second; - key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(data.first)), this_en_pol, assign_map(cell->getPort(data.second))); + key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(data.clk_port)), this_en_pol, assign_map(cell->getPort(data.en_port))); unassigned_cells.erase(cell); expand_queue.insert(cell); -- cgit v1.2.3 From 91687d3feae8df0e315232d3989a445e7d452d1f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 19 Aug 2019 12:33:24 -0700 Subject: Add (* abc_arrival *) attribute --- passes/techmap/abc9.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index be2a8d50b..9156381fa 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -965,7 +965,7 @@ struct Abc9Pass : public Pass { vector lut_costs; markgroups = false; -#if 0 +#if 1 cleanup = false; show_tempdir = true; #endif -- cgit v1.2.3 From e29df7d5fa507657994e974630e89511a205ff1e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 19 Aug 2019 12:44:43 -0700 Subject: Remove debug --- passes/techmap/abc9.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 9156381fa..be2a8d50b 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -965,7 +965,7 @@ struct Abc9Pass : public Pass { vector lut_costs; markgroups = false; -#if 1 +#if 0 cleanup = false; show_tempdir = true; #endif -- cgit v1.2.3 From 505d062daf0e2600dacf04cf18d97b279bd58d72 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 20 Aug 2019 13:33:31 -0700 Subject: Fix use of {CLK,EN}_POLARITY, also add a FIXME --- passes/techmap/abc9.cc | 78 +++++++++----------------------------------------- 1 file changed, 13 insertions(+), 65 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 576fb8542..c7dc67c62 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -645,9 +645,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri if (existing_cell) { cell->parameters = existing_cell->parameters; cell->attributes = existing_cell->attributes; - - cell->attributes.erase("\\abc_flop_clk_pol"); - cell->attributes.erase("\\abc_flop_en_pol"); } else { cell->parameters = mapped_cell->parameters; @@ -1204,11 +1201,7 @@ struct Abc9Pass : public Pass { pool seen_cells; struct flop_data_t { IdString clk_port; - IdString clk_pol_param; - bool clk_pol; IdString en_port; - IdString en_pol_param; - bool en_pol; }; dict flop_data; @@ -1262,39 +1255,7 @@ struct Abc9Pass : public Pass { if (abc_flop_en == IdString()) log_error("'abc_flop_en' attribute not found on any ports on module '%s'.\n", log_id(cell->type)); - auto jt = inst_module->attributes.find("\\abc_flop_clk_pol"); - if (jt == inst_module->attributes.end()) - log_error("'abc_flop_clk_pol' attribute not found on module '%s'.\n", log_id(inst_module)); - IdString abc_flop_clk_pol_param; - bool abc_flop_clk_pol; - if (jt->second.flags == RTLIL::ConstFlags::CONST_FLAG_STRING) { - auto param = jt->second.decode_string(); - abc_flop_clk_pol = (param[0] == '!'); - if (abc_flop_clk_pol) - abc_flop_clk_pol_param = RTLIL::escape_id(param.substr(1)); - else - abc_flop_clk_pol_param = RTLIL::escape_id(param); - } - else - abc_flop_clk_pol = !jt->second.as_bool(); - jt = inst_module->attributes.find("\\abc_flop_en_pol"); - if (jt == inst_module->attributes.end()) - log_error("'abc_flop_en_pol' attribute not found on module '%s'.\n", log_id(inst_module)); - IdString abc_flop_en_pol_param; - bool abc_flop_en_pol; - if (jt->second.flags == RTLIL::ConstFlags::CONST_FLAG_STRING) { - auto param = jt->second.decode_string(); - abc_flop_en_pol = (param[0] == '!'); - if (abc_flop_en_pol) - abc_flop_en_pol_param = RTLIL::escape_id(param.substr(1)); - else - abc_flop_en_pol_param = RTLIL::escape_id(param); - } - else - abc_flop_en_pol = !jt->second.as_bool(); - - it = flop_data.insert(std::make_pair(cell->type, flop_data_t{abc_flop_clk, abc_flop_clk_pol_param, abc_flop_clk_pol, - abc_flop_en, abc_flop_en_pol_param, abc_flop_en_pol})).first; + it = flop_data.insert(std::make_pair(cell->type, flop_data_t{abc_flop_clk, abc_flop_en})).first; } else { it = flop_data.find(cell->type); @@ -1304,30 +1265,15 @@ struct Abc9Pass : public Pass { const auto &data = it->second; - bool this_clk_pol; - if (data.clk_pol_param == IdString()) - this_clk_pol = data.clk_pol; - else { - auto param = data.clk_pol_param; - auto jt = cell->parameters.find(param); - if (jt == cell->parameters.end()) - log_error("'abc_flop_clk_pol' value '%s' is not a parameter on module '%s'.\n", param.c_str(), log_id(cell->type)); - this_clk_pol = jt->second.as_bool(); - if (data.clk_pol) - this_clk_pol = !this_clk_pol; - } - bool this_en_pol; - if (data.en_pol_param == IdString()) - this_en_pol = data.en_pol; - else { - auto param = data.en_pol_param; - auto jt = cell->parameters.find(param); - if (jt == cell->parameters.end()) - log_error("'abc_flop_en_pol' value '%s' is not a parameter on module '%s'.\n", param.c_str(), log_id(cell->type)); - this_en_pol = jt->second.as_bool(); - if (data.en_pol) - this_en_pol = !this_en_pol; - } + auto jt = cell->parameters.find("\\CLK_POLARITY"); + if (jt == cell->parameters.end()) + log_error("'CLK_POLARITY' is not a parameter on module '%s'.\n", log_id(cell->type)); + bool this_clk_pol = jt->second.as_bool(); + + jt = cell->parameters.find("\\EN_POLARITY"); + if (jt == cell->parameters.end()) + log_error("'EN_POLARITY' is not a parameter on module '%s'.\n", log_id(cell->type)); + bool this_en_pol = jt->second.as_bool(); key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(data.clk_port)), this_en_pol, assign_map(cell->getPort(data.en_port))); @@ -1416,9 +1362,10 @@ struct Abc9Pass : public Pass { std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first))); design->selection_stack.emplace_back(false); - RTLIL::Selection& sel = design->selection_stack.back(); for (auto &it : assigned_cells) { + // FIXME: abc9_module calls below can delete cells, + // leaving a dangling pointer here... clk_polarity = std::get<0>(it.first); clk_sig = assign_map(std::get<1>(it.first)); en_polarity = std::get<2>(it.first); @@ -1427,6 +1374,7 @@ struct Abc9Pass : public Pass { pool assigned_names; for (auto i : it.second) assigned_names.insert(i->name); + RTLIL::Selection& sel = design->selection_stack.back(); sel.selected_members[mod->name] = std::move(assigned_names); abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, !clk_sig.empty(), "$", -- cgit v1.2.3 From fad15d276dd9746b41a2d3e1592285ad4362fe21 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 20 Aug 2019 18:08:58 -0700 Subject: retime_mode -> dff_mode --- passes/techmap/abc9.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index c7dc67c62..29929f80b 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -269,7 +269,7 @@ struct abc_output_filter }; void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, - bool cleanup, vector lut_costs, bool /*retime_mode*/, std::string clk_str, + bool cleanup, vector lut_costs, bool /*dff_mode*/, std::string clk_str, bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode, bool show_tempdir, std::string box_file, std::string lut_file, std::string wire_delay, const dict &box_lookup, @@ -309,7 +309,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0)); } - //if (retime_mode && clk_sig.empty()) + //if (dff_mode && clk_sig.empty()) // log_cmd_error("Clock domain %s not found.\n", clk_str.c_str()); std::string tempdir_name = "/tmp/yosys-abc-XXXXXX"; @@ -383,7 +383,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri fprintf(f, "%s\n", abc_script.c_str()); fclose(f); - if (/*retime_mode ||*/ !clk_str.empty()) + if (/*dff_mode ||*/ !clk_str.empty()) { if (clk_sig.size() == 0) log("No%s clock domain found. Not extracting any FF cells.\n", clk_str.empty() ? "" : " matching"); @@ -957,7 +957,7 @@ struct Abc9Pass : public Pass { #endif std::string script_file, clk_str, box_file, lut_file; std::string delay_target, lutin_shared = "-S 1", wire_delay; - bool fast_mode = false, /*retime_mode = false,*/ keepff = false, cleanup = true; + bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true; bool show_tempdir = false; vector lut_costs; markgroups = false; @@ -1049,12 +1049,12 @@ struct Abc9Pass : public Pass { continue; } //if (arg == "-retime") { - // retime_mode = true; + // dff_mode = true; // continue; //} //if (arg == "-clk" && argidx+1 < args.size()) { // clk_str = args[++argidx]; - // retime_mode = true; + // dff_mode = true; // continue; //} //if (arg == "-keepff") { @@ -1169,7 +1169,7 @@ struct Abc9Pass : public Pass { assign_map.set(mod); - if (true || /*!dff_mode ||*/ !clk_str.empty()) { + if (!dff_mode || !clk_str.empty()) { design->selection_stack.emplace_back(false); RTLIL::Selection& sel = design->selection_stack.back(); -- cgit v1.2.3 From 091bf4a18b2f4bf84fe62b61577c88d961468b3c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 20 Aug 2019 18:16:37 -0700 Subject: Remove sequential extension --- passes/techmap/abc9.cc | 88 ++++++++++++-------------------------------------- 1 file changed, 20 insertions(+), 68 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 29929f80b..919c4ce53 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -551,7 +551,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri dict abc_box; vector boxes; for (auto cell : module->selected_cells()) { - if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC_FF_))) { + if (cell->type.in(ID($_AND_), ID($_NOT_))) { module->remove(cell); continue; } @@ -651,7 +651,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri cell->attributes = mapped_cell->attributes; } - auto abc_flop = mapped_cell->attributes.count("\\abc_flop"); for (auto &conn : mapped_cell->connections()) { RTLIL::SigSpec newsig; for (auto c : conn.second.chunks()) { @@ -664,17 +663,15 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri } cell->setPort(conn.first, newsig); - if (!abc_flop) { - if (cell->input(conn.first)) { - for (auto i : newsig) - bit2sinks[i].push_back(cell); - for (auto i : conn.second) - bit_users[i].insert(mapped_cell->name); - } - if (cell->output(conn.first)) - for (auto i : conn.second) - bit_drivers[i].insert(mapped_cell->name); + if (cell->input(conn.first)) { + for (auto i : newsig) + bit2sinks[i].push_back(cell); + for (auto i : conn.second) + bit_users[i].insert(mapped_cell->name); } + if (cell->output(conn.first)) + for (auto i : conn.second) + bit_drivers[i].insert(mapped_cell->name); } } @@ -1170,7 +1167,6 @@ struct Abc9Pass : public Pass { assign_map.set(mod); if (!dff_mode || !clk_str.empty()) { - design->selection_stack.emplace_back(false); RTLIL::Selection& sel = design->selection_stack.back(); sel.select(mod); @@ -1198,13 +1194,6 @@ struct Abc9Pass : public Pass { std::map> cell_to_bit, cell_to_bit_up, cell_to_bit_down; std::map> bit_to_cell, bit_to_cell_up, bit_to_cell_down; - pool seen_cells; - struct flop_data_t { - IdString clk_port; - IdString en_port; - }; - dict flop_data; - for (auto cell : all_cells) { clkdomain_t key; @@ -1225,57 +1214,20 @@ struct Abc9Pass : public Pass { } } - decltype(flop_data)::iterator it; - if (seen_cells.insert(cell->type).second) { - RTLIL::Module* inst_module = design->module(cell->type); - if (!inst_module) - continue; - - if (!inst_module->attributes.count("\\abc_flop")) - continue; - - IdString abc_flop_clk, abc_flop_en; - for (auto port_name : inst_module->ports) { - auto wire = inst_module->wire(port_name); - log_assert(wire); - if (wire->attributes.count("\\abc_flop_clk")) { - if (abc_flop_clk != IdString()) - log_error("More than one port has the 'abc_flop_clk' attribute set on module '%s'.\n", log_id(cell->type)); - abc_flop_clk = port_name; - } - if (wire->attributes.count("\\abc_flop_en")) { - if (abc_flop_en != IdString()) - log_error("More than one port has the 'abc_flop_en' attribute set on module '%s'.\n", log_id(cell->type)); - abc_flop_en = port_name; - } - } - - if (abc_flop_clk == IdString()) - log_error("'abc_flop_clk' attribute not found on any ports on module '%s'.\n", log_id(cell->type)); - if (abc_flop_en == IdString()) - log_error("'abc_flop_en' attribute not found on any ports on module '%s'.\n", log_id(cell->type)); - - it = flop_data.insert(std::make_pair(cell->type, flop_data_t{abc_flop_clk, abc_flop_en})).first; + if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) + { + key = clkdomain_t(cell->type == ID($_DFF_P_), assign_map(cell->getPort(ID(C))), true, RTLIL::SigSpec()); } - else { - it = flop_data.find(cell->type); - if (it == flop_data.end()) - continue; + else + if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) + { + bool this_clk_pol = cell->type.in(ID($_DFFE_PN_), ID($_DFFE_PP_)); + bool this_en_pol = cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)); + key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(ID(C))), this_en_pol, assign_map(cell->getPort(ID(E)))); } + else + continue; - const auto &data = it->second; - - auto jt = cell->parameters.find("\\CLK_POLARITY"); - if (jt == cell->parameters.end()) - log_error("'CLK_POLARITY' is not a parameter on module '%s'.\n", log_id(cell->type)); - bool this_clk_pol = jt->second.as_bool(); - - jt = cell->parameters.find("\\EN_POLARITY"); - if (jt == cell->parameters.end()) - log_error("'EN_POLARITY' is not a parameter on module '%s'.\n", log_id(cell->type)); - bool this_en_pol = jt->second.as_bool(); - - key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(data.clk_port)), this_en_pol, assign_map(cell->getPort(data.en_port))); unassigned_cells.erase(cell); expand_queue.insert(cell); -- cgit v1.2.3 From 57493e328ad69b749619bc692130e28ab5c212ee Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 20 Aug 2019 19:48:16 -0700 Subject: techmap -max_iter to apply to each module individually --- passes/techmap/techmap.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'passes') diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index b271c8781..a6c1214a7 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -943,7 +943,8 @@ struct TechmapPass : public Pass { log(" instead of inlining them.\n"); log("\n"); log(" -max_iter \n"); - log(" only run the specified number of iterations.\n"); + log(" only run the specified number of iterations for each module.\n"); + log(" default: unlimited\n"); log("\n"); log(" -recursive\n"); log(" instead of the iterative breadth-first algorithm use a recursive\n"); @@ -1157,15 +1158,16 @@ struct TechmapPass : public Pass { RTLIL::Module *module = *worker.module_queue.begin(); worker.module_queue.erase(module); + int module_max_iter = max_iter; bool did_something = true; std::set handled_cells; while (did_something) { did_something = false; - if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false)) - did_something = true; + if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false)) + did_something = true; if (did_something) module->check(); - if (max_iter > 0 && --max_iter == 0) + if (module_max_iter > 0 && --module_max_iter == 0) break; } } -- cgit v1.2.3 From 4cc74346f11e96b9a2bce1c984c674a22771a00a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 20 Aug 2019 20:27:05 -0700 Subject: Fix compile error --- passes/pmgen/ice40_dsp.cc | 4 ---- passes/pmgen/ice40_dsp.pmg | 18 ++++++++++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index a1a397b83..31e11c742 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -23,10 +23,6 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -template inline bool includes(const T &lhs, const T &rhs) { - return std::includes(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); -} -#include #include "passes/pmgen/ice40_dsp_pm.h" void create_ice40_dsp(ice40_dsp_pm &pm) diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index cf7957ff3..24bdfd3f2 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -34,7 +34,6 @@ match ffA if mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool() if !sigAset.empty() select ffA->type.in($dff) - filter includes(port(ffA, \Q).to_sigbit_set(), sigAset) optional endmatch @@ -42,6 +41,10 @@ code sigA clock clock_pol sigA = port(mul, \A); if (ffA) { + auto ffAset = port(ffA, \Q).to_sigbit_set(); + if (!std::includes(ffAset.begin(), ffAset.end(), sigAset.begin(), sigAset.end())) + reject; + for (auto b : port(ffA, \Q)) if (b.wire->get_bool_attribute(\keep)) reject; @@ -57,7 +60,6 @@ match ffB if mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool() if !sigBset.empty() select ffB->type.in($dff) - filter includes(port(ffB, \Q).to_sigbit_set(), sigBset) optional endmatch @@ -65,6 +67,10 @@ code sigB clock clock_pol sigB = port(mul, \B); if (ffB) { + auto ffBset = port(ffB, \Q).to_sigbit_set(); + if (!std::includes(ffBset.begin(), ffBset.end(), sigBset.begin(), sigBset.end())) + reject; + for (auto b : port(ffB, \Q)) if (b.wire->get_bool_attribute(\keep)) reject; @@ -207,7 +213,9 @@ code if (ffO_lo) { SigSpec O = sigOused.extract(0,std::min(16,param(ffO_lo, \WIDTH).as_int())); O.remove_const(); - if (!includes(port(ffO_lo, \D).to_sigbit_set(), O.to_sigbit_set())) + auto ffO_loSet = port(ffO_lo, \D).to_sigbit_set(); + auto Oset = O.to_sigbit_set(); + if (!std::includes(ffO_loSet.begin(), ffO_loSet.end(), Oset.begin(), Oset.end())) reject; } endcode @@ -223,7 +231,9 @@ code if (ffO_hi) { SigSpec O = sigOused.extract_end(16); O.remove_const(); - if (!includes(port(ffO_hi, \D).to_sigbit_set(), O.to_sigbit_set())) + auto ffO_hiSet = port(ffO_hi, \D).to_sigbit_set(); + auto Oset = O.to_sigbit_set(); + if (!std::includes(ffO_hiSet.begin(), ffO_hiSet.end(), Oset.begin(), Oset.end())) reject; } endcode -- cgit v1.2.3 From 48c424e45bceec55b71dd64c987b2c7eafe7a113 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 23 Aug 2019 13:46:05 -0700 Subject: Cleanup --- passes/techmap/abc9.cc | 189 +++++++++++++++---------------------------------- 1 file changed, 59 insertions(+), 130 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 919c4ce53..968c68b70 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -76,8 +76,7 @@ inline std::string remap_name(RTLIL::IdString abc_name) return stringf("$abc$%d$%s", map_autoidx, abc_name.c_str()+1); } -void handle_loops(RTLIL::Design *design, - const dict> &scc_break_inputs) +void handle_loops(RTLIL::Design *design) { Pass::call(design, "scc -set_attr abc_scc_id {}"); @@ -85,7 +84,7 @@ void handle_loops(RTLIL::Design *design, // cell in the component, and select (and mark) all its output // wires pool ids_seen; - for (auto cell : module->selected_cells()) { + for (auto cell : module->cells()) { auto it = cell->attributes.find(ID(abc_scc_id)); if (it != cell->attributes.end()) { auto r = ids_seen.insert(it->second); @@ -114,30 +113,6 @@ void handle_loops(RTLIL::Design *design, } cell->attributes.erase(it); } - - auto jt = scc_break_inputs.find(cell->type); - if (jt != scc_break_inputs.end()) - for (auto port_name : jt->second) { - RTLIL::SigSpec sig; - auto &rhs = cell->connections_.at(port_name); - for (auto b : rhs) { - Wire *w = b.wire; - if (!w) continue; - w->port_output = true; - w->set_bool_attribute(ID(abc_scc_break)); - w = module->wire(stringf("%s.abci", w->name.c_str())); - if (!w) { - w = module->addWire(stringf("%s.abci", b.wire->name.c_str()), GetSize(b.wire)); - w->port_input = true; - } - else { - log_assert(b.offset < GetSize(w)); - log_assert(w->port_input); - } - sig.append(RTLIL::SigBit(w, b.offset)); - } - rhs = sig; - } } module->fixup_ports(); @@ -269,11 +244,10 @@ struct abc_output_filter }; void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, - bool cleanup, vector lut_costs, bool /*dff_mode*/, std::string clk_str, + bool cleanup, vector lut_costs, bool dff_mode, std::string clk_str, bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode, bool show_tempdir, std::string box_file, std::string lut_file, - std::string wire_delay, const dict &box_lookup, - const dict> &scc_break_inputs + std::string wire_delay, const dict &box_lookup ) { module = current_module; @@ -309,8 +283,8 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0)); } - //if (dff_mode && clk_sig.empty()) - // log_cmd_error("Clock domain %s not found.\n", clk_str.c_str()); + if (dff_mode && clk_sig.empty()) + log_cmd_error("Clock domain %s not found.\n", clk_str.c_str()); std::string tempdir_name = "/tmp/yosys-abc-XXXXXX"; if (!cleanup) @@ -383,7 +357,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri fprintf(f, "%s\n", abc_script.c_str()); fclose(f); - if (/*dff_mode ||*/ !clk_str.empty()) + if (dff_mode || !clk_str.empty()) { if (clk_sig.size() == 0) log("No%s clock domain found. Not extracting any FF cells.\n", clk_str.empty() ? "" : " matching"); @@ -413,16 +387,13 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri RTLIL::Selection& sel = design->selection_stack.back(); sel.select(module); - handle_loops(design, scc_break_inputs); + handle_loops(design); Pass::call(design, "aigmap"); //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); -#if 0 - Pass::call(design, stringf("write_verilog -noexpr -norename %s/before.v", tempdir_name.c_str())); -#endif Pass::call(design, stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str())); std::string buffer; @@ -531,12 +502,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri for (int i = 0; i < GetSize(w); i++) output_bits.insert({wire, i}); } - - auto jt = w->attributes.find("\\init"); - if (jt != w->attributes.end()) { - auto r = remap_wire->attributes.insert(std::make_pair("\\init", jt->second)); - log_assert(r.second); - } } for (auto &it : module->connections_) { @@ -550,7 +515,8 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri dict abc_box; vector boxes; - for (auto cell : module->selected_cells()) { + for (const auto &it : module->cells_) { + auto cell = it.second; if (cell->type.in(ID($_AND_), ID($_NOT_))) { module->remove(cell); continue; @@ -570,23 +536,25 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri dict> bit2sinks; std::map cell_stats; - for (auto mapped_cell : mapped_mod->cells()) + for (auto c : mapped_mod->cells()) { - toposort.node(mapped_cell->name); + toposort.node(c->name); RTLIL::Cell *cell = nullptr; - if (mapped_cell->type == ID($_NOT_)) { - RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A); - RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y); + if (c->type == ID($_NOT_)) { + RTLIL::SigBit a_bit = c->getPort(ID::A); + RTLIL::SigBit y_bit = c->getPort(ID::Y); + bit_users[a_bit].insert(c->name); + bit_drivers[y_bit].insert(c->name); if (!a_bit.wire) { - mapped_cell->setPort(ID::Y, module->addWire(NEW_ID)); + c->setPort(ID::Y, module->addWire(NEW_ID)); RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name)); log_assert(wire); module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1); } - else { - RTLIL::Cell* driving_lut = nullptr; + else if (!lut_costs.empty() || !lut_file.empty()) { + RTLIL::Cell* driver_lut = nullptr; // ABC can return NOT gates that drive POs if (!a_bit.wire->port_input) { // If it's not a NOT gate that that comes from a PI directly, @@ -598,46 +566,46 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri driver_name = stringf("%s$lut", a_bit.wire->name.c_str()); else driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset); - driving_lut = mapped_mod->cell(driver_name); + driver_lut = mapped_mod->cell(driver_name); } - if (!driving_lut) { + if (!driver_lut) { // If a driver couldn't be found (could be from PI or box CI) // then implement using a LUT - cell = module->addLut(remap_name(stringf("%s$lut", mapped_cell->name.c_str())), + cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())), RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset), RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset), RTLIL::Const::from_string("01")); bit2sinks[cell->getPort(ID::A)].push_back(cell); cell_stats[ID($lut)]++; - bit_users[a_bit].insert(mapped_cell->name); - bit_drivers[y_bit].insert(mapped_cell->name); } else - not2drivers[mapped_cell] = driving_lut; + not2drivers[c] = driver_lut; continue; } + else + log_abort(); if (cell && markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; continue; } - cell_stats[mapped_cell->type]++; + cell_stats[c->type]++; RTLIL::Cell *existing_cell = nullptr; - if (mapped_cell->type == ID($lut)) { - if (GetSize(mapped_cell->getPort(ID::A)) == 1 && mapped_cell->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) { - SigSpec my_a = module->wires_.at(remap_name(mapped_cell->getPort(ID::A).as_wire()->name)); - SigSpec my_y = module->wires_.at(remap_name(mapped_cell->getPort(ID::Y).as_wire()->name)); + if (c->type == ID($lut)) { + if (GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) { + SigSpec my_a = module->wires_.at(remap_name(c->getPort(ID::A).as_wire()->name)); + SigSpec my_y = module->wires_.at(remap_name(c->getPort(ID::Y).as_wire()->name)); module->connect(my_y, my_a); - if (markgroups) mapped_cell->attributes[ID(abcgroup)] = map_autoidx; + if (markgroups) c->attributes[ID(abcgroup)] = map_autoidx; log_abort(); continue; } - cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); + cell = module->addCell(remap_name(c->name), c->type); } else { - existing_cell = module->cell(mapped_cell->name); + existing_cell = module->cell(c->name); log_assert(existing_cell); - cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); + cell = module->addCell(remap_name(c->name), c->type); module->swap_names(cell, existing_cell); } @@ -647,11 +615,10 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri cell->attributes = existing_cell->attributes; } else { - cell->parameters = mapped_cell->parameters; - cell->attributes = mapped_cell->attributes; + cell->parameters = c->parameters; + cell->attributes = c->attributes; } - - for (auto &conn : mapped_cell->connections()) { + for (auto &conn : c->connections()) { RTLIL::SigSpec newsig; for (auto c : conn.second.chunks()) { if (c.width == 0) @@ -667,11 +634,11 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri for (auto i : newsig) bit2sinks[i].push_back(cell); for (auto i : conn.second) - bit_users[i].insert(mapped_cell->name); + bit_users[i].insert(c->name); } if (cell->output(conn.first)) for (auto i : conn.second) - bit_drivers[i].insert(mapped_cell->name); + bit_drivers[i].insert(c->name); } } @@ -697,27 +664,29 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri } for (auto &it : cell_stats) - log("ABC RESULTS: %15s cells: %8d\n", log_id(it.first), it.second); + log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second); int in_wires = 0, out_wires = 0; // Stitch in mapped_mod's inputs/outputs into module - for (auto port_name : mapped_mod->ports) { - RTLIL::Wire *port = mapped_mod->wire(port_name); - log_assert(port); - RTLIL::Wire *wire = module->wire(port->name); + for (auto &it : mapped_mod->wires_) { + RTLIL::Wire *w = it.second; + if (!w->port_input && !w->port_output) + continue; + RTLIL::Wire *wire = module->wire(w->name); log_assert(wire); - RTLIL::Wire *remap_wire = module->wire(remap_name(port->name)); + RTLIL::Wire *remap_wire = module->wire(remap_name(w->name)); RTLIL::SigSpec signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire)); log_assert(GetSize(signal) >= GetSize(remap_wire)); + log_assert(w->port_input || w->port_output); RTLIL::SigSig conn; - if (port->port_input) { + if (w->port_input) { conn.first = remap_wire; conn.second = signal; in_wires++; module->connect(conn); } - if (port->port_output) { + if (w->port_output) { conn.first = signal; conn.second = remap_wire; out_wires++; @@ -730,21 +699,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri for (auto driver_cell : bit_drivers.at(it.first)) for (auto user_cell : it.second) toposort.edge(driver_cell, user_cell); -#if 0 - toposort.analyze_loops = true; -#endif bool no_loops YS_ATTRIBUTE(unused) = toposort.sort(); -#if 0 - unsigned i = 0; - for (auto &it : toposort.loops) { - log(" loop %d\n", i++); - for (auto cell_name : it) { - auto cell = mapped_mod->cell(cell_name); - log_assert(cell); - log("\t%s (%s @ %s)\n", log_id(cell), log_id(cell->type), cell->get_src_attribute().c_str()); - } - } -#endif log_assert(no_loops); for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) { @@ -1045,7 +1000,7 @@ struct Abc9Pass : public Pass { fast_mode = true; continue; } - //if (arg == "-retime") { + //if (arg == "-dff") { // dff_mode = true; // continue; //} @@ -1085,11 +1040,7 @@ struct Abc9Pass : public Pass { } extra_args(args, argidx, design); - if (lut_costs.empty() && lut_file.empty()) - log_cmd_error("abc9 must be called with '-lut' or '-luts'\n"); - dict box_lookup; - dict> scc_break_inputs; for (auto m : design->modules()) { auto it = m->attributes.find(ID(abc_box_id)); if (it == m->attributes.end()) @@ -1107,17 +1058,13 @@ struct Abc9Pass : public Pass { for (auto p : m->ports) { auto w = m->wire(p); log_assert(w); - if (w->port_input) { - if (w->attributes.count(ID(abc_scc_break))) - scc_break_inputs[m->name].insert(p); - if (w->attributes.count(ID(abc_carry))) { + if (w->attributes.count(ID(abc_carry))) { + if (w->port_input) { if (carry_in) log_error("Module '%s' contains more than one 'abc_carry' input port.\n", log_id(m)); carry_in = w; } - } - if (w->port_output) { - if (w->attributes.count(ID(abc_carry))) { + else if (w->port_output) { if (carry_out) log_error("Module '%s' contains more than one 'abc_carry' input port.\n", log_id(m)); carry_out = w; @@ -1167,14 +1114,9 @@ struct Abc9Pass : public Pass { assign_map.set(mod); if (!dff_mode || !clk_str.empty()) { - design->selection_stack.emplace_back(false); - RTLIL::Selection& sel = design->selection_stack.back(); - sel.select(mod); - - abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, false, clk_str, keepff, + abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, dff_mode, clk_str, keepff, delay_target, lutin_shared, fast_mode, show_tempdir, - box_file, lut_file, wire_delay, box_lookup, scc_break_inputs); - design->selection_stack.pop_back(); + box_file, lut_file, wire_delay, box_lookup); continue; } @@ -1194,7 +1136,8 @@ struct Abc9Pass : public Pass { std::map> cell_to_bit, cell_to_bit_up, cell_to_bit_down; std::map> bit_to_cell, bit_to_cell_up, bit_to_cell_down; - for (auto cell : all_cells) { + for (auto cell : all_cells) + { clkdomain_t key; for (auto &conn : cell->connections()) @@ -1228,7 +1171,6 @@ struct Abc9Pass : public Pass { else continue; - unassigned_cells.erase(cell); expand_queue.insert(cell); expand_queue_up.insert(cell); @@ -1313,29 +1255,16 @@ struct Abc9Pass : public Pass { std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)), std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first))); - design->selection_stack.emplace_back(false); - for (auto &it : assigned_cells) { - // FIXME: abc9_module calls below can delete cells, - // leaving a dangling pointer here... 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)); - - pool assigned_names; - for (auto i : it.second) - assigned_names.insert(i->name); - RTLIL::Selection& sel = design->selection_stack.back(); - sel.selected_members[mod->name] = std::move(assigned_names); - abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, !clk_sig.empty(), "$", keepff, delay_target, lutin_shared, fast_mode, show_tempdir, - box_file, lut_file, wire_delay, box_lookup, scc_break_inputs); + box_file, lut_file, wire_delay, box_lookup); assign_map.set(mod); } - - design->selection_stack.pop_back(); } assign_map.clear(); -- cgit v1.2.3 From a45c09c8d1320d311fbda8d615d39117acb8f70b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 28 Aug 2019 15:31:55 -0700 Subject: Account for D port being a constant --- passes/pmgen/xilinx_srl.pmg | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_srl.pmg b/passes/pmgen/xilinx_srl.pmg index 45d44247a..b18119b87 100644 --- a/passes/pmgen/xilinx_srl.pmg +++ b/passes/pmgen/xilinx_srl.pmg @@ -105,7 +105,7 @@ endcode match next select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1) select !next->has_keep_attr() - select !port(next, \D)[0].wire->get_bool_attribute(\keep) + select port(next, \D)[0].wire && !port(next, \D)[0].wire->get_bool_attribute(\keep) select nusers(port(next, \Q)) == 2 index next->type === first->type index port(next, \Q) === port(first, \D) @@ -132,7 +132,7 @@ match next semioptional select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1) select !next->has_keep_attr() - select !port(next, \D)[0].wire->get_bool_attribute(\keep) + select port(next, \D)[0].wire && !port(next, \D)[0].wire->get_bool_attribute(\keep) select nusers(port(next, \Q)) == 2 index next->type === chain.back()->type index port(next, \Q) === port(chain.back(), \D) @@ -201,7 +201,7 @@ endcode match first select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, $dff, $dffe) select !first->has_keep_attr() - select !port(first, \Q)[0].wire->get_bool_attribute(\keep) + select port(first, \Q)[0].wire && !port(first, \Q)[0].wire->get_bool_attribute(\keep) slice idx GetSize(port(first, \Q)) select nusers(port(first, \Q)[idx]) <= 2 index port(first, \Q)[idx] === port(shiftx, \A)[shiftx_width-1] @@ -272,7 +272,7 @@ match next semioptional select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, $dff, $dffe) select !next->has_keep_attr() - select !port(next, \D)[0].wire->get_bool_attribute(\keep) + select port(next, \D)[0].wire && !port(next, \D)[0].wire->get_bool_attribute(\keep) slice idx GetSize(port(next, \Q)) select nusers(port(next, \Q)[idx]) <= 3 index next->type === chain.back().first->type -- cgit v1.2.3 From 116c2496011aeeac9847d69af597a0db58209793 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 28 Aug 2019 19:59:25 -0700 Subject: -auto-top should check $abstract (deferred) modules with (* top *) --- passes/hierarchy/hierarchy.cc | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'passes') diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index fd95b94b2..ad795c69f 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -808,6 +808,37 @@ struct HierarchyPass : public Pass { if (mod_it.second->get_bool_attribute("\\top")) top_mod = mod_it.second; + if (top_mod != nullptr && auto_top_mode) { + IdString abstract_id = top_mod->name; + IdString top_name = abstract_id; + if (top_name.begins_with("$abstract")) + top_name = top_name.substr(strlen("$abstract")); + top_mod = design->module(top_name); + + dict top_parameters; + for (auto ¶ : parameters) { + SigSpec sig_value; + if (!RTLIL::SigSpec::parse(sig_value, NULL, para.second)) + log_cmd_error("Can't decode value '%s'!\n", para.second.c_str()); + top_parameters[RTLIL::escape_id(para.first)] = sig_value.as_const(); + } + + if (top_mod == nullptr && design->module(abstract_id)) + top_mod = design->module(design->module(abstract_id)->derive(design, top_parameters)); + else if (top_mod != nullptr && !top_parameters.empty()) + top_mod = design->module(top_mod->derive(design, top_parameters)); + + if (top_mod != nullptr && top_mod->name != top_name) { + Module *m = top_mod->clone(); + m->name = top_name; + Module *old_mod = design->module(top_name); + if (old_mod) + design->remove(old_mod); + design->add(m); + top_mod = m; + } + } + if (top_mod == nullptr && auto_top_mode) { log_header(design, "Finding top of design hierarchy..\n"); dict db; -- cgit v1.2.3 From c4e53108230c246ecf1b014b11c240b71ed39a8a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 28 Aug 2019 20:58:55 -0700 Subject: Use a dummy box file if none specified --- passes/techmap/abc9.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 968c68b70..11fe9c4a5 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -1027,9 +1027,6 @@ struct Abc9Pass : public Pass { } if (arg == "-box" && argidx+1 < args.size()) { box_file = args[++argidx]; - rewrite_filename(box_file); - if (!box_file.empty() && !is_absolute_path(box_file)) - box_file = std::string(pwd) + "/" + box_file; continue; } if (arg == "-W" && argidx+1 < args.size()) { @@ -1040,6 +1037,14 @@ struct Abc9Pass : public Pass { } extra_args(args, argidx, design); + // ABC expects a box file for XAIG + if (box_file.empty()) + box_file = "+/dummy.box"; + + rewrite_filename(box_file); + if (!box_file.empty() && !is_absolute_path(box_file)) + box_file = std::string(pwd) + "/" + box_file; + dict box_lookup; for (auto m : design->modules()) { auto it = m->attributes.find(ID(abc_box_id)); -- cgit v1.2.3 From 4e782f1509e74bbb69ac99fa3c443112327e4f39 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 30 Aug 2019 11:02:10 -0700 Subject: New pmgen requires explicit accept --- passes/pmgen/xilinx_dsp.pmg | 2 ++ 1 file changed, 2 insertions(+) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 7f1958d5d..47e6a0050 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -176,4 +176,6 @@ code ffP clock clock = c; } + + accept; endcode -- cgit v1.2.3 From 89359b6927c012f5d683dd37401d36566ad0c419 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 30 Aug 2019 14:00:40 -0700 Subject: Missing dep for test_pmgen --- passes/pmgen/Makefile.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index 1c66f47c2..fa3b1ef2f 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -4,7 +4,7 @@ # -------------------------------------- OBJS += passes/pmgen/test_pmgen.o -passes/pmgen/test_pmgen.o: passes/pmgen/test_pmgen_pm.h passes/pmgen/ice40_dsp_pm.h passes/pmgen/peepopt_pm.h +passes/pmgen/test_pmgen.o: passes/pmgen/test_pmgen_pm.h passes/pmgen/ice40_dsp_pm.h passes/pmgen/peepopt_pm.h passes/pmgen/xilinx_srl_pm.h $(eval $(call add_extra_objs,passes/pmgen/test_pmgen_pm.h)) # -------------------------------------- -- cgit v1.2.3 From 2983a35dc058a5f5a1ab7b23cc55dd6f83667d88 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 30 Aug 2019 15:00:40 -0700 Subject: Update comment --- passes/pmgen/ice40_dsp.pmg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 24bdfd3f2..8221cdb69 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -89,11 +89,11 @@ code sigB clock clock_pol endcode match ffFJKG + // Ensure pipeline register is not already used if mul->type != \SB_MAC16 || (!param(mul, \TOP_8x8_MULT_REG).as_bool() && !param(mul, \BOT_8x8_MULT_REG).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG2).as_bool()) select ffFJKG->type.in($dff) select nusers(port(ffFJKG, \D)) == 2 index port(ffFJKG, \D) === sigH - // Ensure pipeline register is not already used optional endmatch -- cgit v1.2.3 From 390cf34d0a8f815ea9828f9a455b36164f9d5607 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 30 Aug 2019 15:00:56 -0700 Subject: Add support for ffM --- passes/pmgen/xilinx_dsp.cc | 12 ++++++++++++ passes/pmgen/xilinx_dsp.pmg | 39 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index e7b72e312..105ad1fa1 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -39,6 +39,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("ffB: %s\n", log_id(st.ffB, "--")); log("dsp: %s\n", log_id(st.dsp, "--")); log("addAB: %s\n", log_id(st.addAB, "--")); + log("ffM: %s\n", log_id(st.ffM, "--")); log("ffP: %s\n", log_id(st.ffP, "--")); //log("muxP: %s\n", log_id(st.muxP, "--")); log("sigPused: %s\n", log_signal(st.sigPused)); @@ -95,6 +96,17 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) // cell->setPort("\\CEB2", st.ffB->getPort("\\EN")); else log_abort(); } + if (st.ffM) { + SigSpec D = st.ffM->getPort("\\D"); + SigSpec Q = st.ffM->getPort("\\Q"); + P.replace(pm.sigmap(D), Q); + cell->setParam("\\MREG", State::S1); + if (st.ffP->type == "$dff") + cell->setPort("\\CEM", State::S1); + //else if (st.ffP->type == "$dffe") + // cell->setPort("\\CEP", st.ffP->getPort("\\EN")); + else log_abort(); + } if (st.ffP) { SigSpec D; //if (st.muxP) diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 47e6a0050..08b432b8e 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -2,7 +2,7 @@ pattern xilinx_dsp state clock state > sigAset sigBset -state sigC sigP sigPused +state sigC sigM sigMused sigP sigPused state addAB match dsp @@ -18,6 +18,12 @@ code sigAset sigBset sigBset = B.to_sigbit_set(); endcode +code sigM + sigM = port(dsp, \P); + //if (GetSize(sigH) <= 10) + // reject; +endcode + match ffA if param(dsp, \AREG).as_int() == 0 if !sigAset.empty() @@ -63,8 +69,35 @@ code clock } endcode -code sigP - sigP = port(dsp, \P); +match ffM + if param(dsp, \MREG).as_int() == 0 + select ffM->type.in($dff) + // DSP48E1 does not support clock inversion + select param(ffM, \CLK_POLARITY).as_bool() + select nusers(port(ffM, \D)) == 2 + //index port(ffM, \D) === sigM.extract(0, GetSize(port(ffM, \D))) // TODO: Why doesn't this work!?! + filter port(ffM, \D) == sigM.extract(0, GetSize(port(ffM, \D))) + filter nusers(sigM.extract_end(param(ffM, \WIDTH).as_int())) == 1 + optional +endmatch + +code clock sigM sigP + if (ffM) { + log_warning("M FOUND!\n"); + sigM = port(ffM, \Q); + for (auto b : sigM) + if (b.wire->get_bool_attribute(\keep)) + reject; + + SigBit c = port(ffB, \CLK).as_bit(); + + if (clock != SigBit() && c != clock) + reject; + + clock = c; + } + + sigP = sigM; endcode match addA -- cgit v1.2.3 From 44a35015b308adbbf5f87408d2928a36245f57e7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 30 Aug 2019 15:01:38 -0700 Subject: Update commented out --- passes/pmgen/xilinx_dsp.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 105ad1fa1..b03fff8ec 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -104,7 +104,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) if (st.ffP->type == "$dff") cell->setPort("\\CEM", State::S1); //else if (st.ffP->type == "$dffe") - // cell->setPort("\\CEP", st.ffP->getPort("\\EN")); + // cell->setPort("\\CEM", st.ffM->getPort("\\EN")); else log_abort(); } if (st.ffP) { -- cgit v1.2.3 From c497114e94286c06fe16a6ae32e2873578a861f4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 30 Aug 2019 15:02:53 -0700 Subject: Another oops --- passes/pmgen/xilinx_dsp.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index b03fff8ec..66fe7736b 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -101,7 +101,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) SigSpec Q = st.ffM->getPort("\\Q"); P.replace(pm.sigmap(D), Q); cell->setParam("\\MREG", State::S1); - if (st.ffP->type == "$dff") + if (st.ffM->type == "$dff") cell->setPort("\\CEM", State::S1); //else if (st.ffP->type == "$dffe") // cell->setPort("\\CEM", st.ffM->getPort("\\EN")); -- cgit v1.2.3 From 15bab02a1b1e20b25b6ac40914e82b31a3756382 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 30 Aug 2019 15:03:12 -0700 Subject: ffM before addAB --- passes/pmgen/xilinx_dsp.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 66fe7736b..50af5de1c 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -38,8 +38,8 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("ffA: %s\n", log_id(st.ffA, "--")); log("ffB: %s\n", log_id(st.ffB, "--")); log("dsp: %s\n", log_id(st.dsp, "--")); - log("addAB: %s\n", log_id(st.addAB, "--")); log("ffM: %s\n", log_id(st.ffM, "--")); + log("addAB: %s\n", log_id(st.addAB, "--")); log("ffP: %s\n", log_id(st.ffP, "--")); //log("muxP: %s\n", log_id(st.muxP, "--")); log("sigPused: %s\n", log_signal(st.sigPused)); -- cgit v1.2.3 From e67f049e3b1c1ed643b86b5237b31075d0f2f212 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 30 Aug 2019 15:03:43 -0700 Subject: Remove debug --- passes/pmgen/xilinx_dsp.pmg | 1 - 1 file changed, 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 08b432b8e..a4e1bf86d 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -83,7 +83,6 @@ endmatch code clock sigM sigP if (ffM) { - log_warning("M FOUND!\n"); sigM = port(ffM, \Q); for (auto b : sigM) if (b.wire->get_bool_attribute(\keep)) -- cgit v1.2.3 From 8f503fe3e65ba9be2ef7438b2f4143f88ea8a025 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 30 Aug 2019 15:30:04 -0700 Subject: autoremove ffM --- passes/pmgen/xilinx_dsp.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 50af5de1c..631b93afa 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -106,6 +106,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) //else if (st.ffP->type == "$dffe") // cell->setPort("\\CEM", st.ffM->getPort("\\EN")); else log_abort(); + pm.autoremove(st.ffM); } if (st.ffP) { SigSpec D; -- cgit v1.2.3 From a09e69dd56da677f016fceeb90a68eead8a85c2f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 30 Aug 2019 16:18:58 -0700 Subject: Fine tune xilinx_dsp pattern matcher --- passes/pmgen/xilinx_dsp.pmg | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index a4e1bf86d..132b09b2b 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -76,8 +76,9 @@ match ffM select param(ffM, \CLK_POLARITY).as_bool() select nusers(port(ffM, \D)) == 2 //index port(ffM, \D) === sigM.extract(0, GetSize(port(ffM, \D))) // TODO: Why doesn't this work!?! + filter GetSize(port(ffM, \D)) <= GetSize(sigM) filter port(ffM, \D) == sigM.extract(0, GetSize(port(ffM, \D))) - filter nusers(sigM.extract_end(param(ffM, \WIDTH).as_int())) == 1 + filter nusers(sigM.extract_end(GetSize(port(ffM, \D)))) <= 1 optional endmatch @@ -88,7 +89,7 @@ code clock sigM sigP if (b.wire->get_bool_attribute(\keep)) reject; - SigBit c = port(ffB, \CLK).as_bit(); + SigBit c = port(ffM, \CLK).as_bit(); if (clock != SigBit() && c != clock) reject; @@ -102,10 +103,11 @@ endcode match addA select addA->type.in($add) select param(addA, \A_SIGNED).as_bool() && param(addA, \B_SIGNED).as_bool() - index nusers(port(addA, \A)) === 2 - //index port(addA, \A) === sigP.extract(0, param(addA, \A_WIDTH).as_int()) - filter param(addA, \A_WIDTH).as_int() <= GetSize(sigP) - filter port(addA, \A) == sigP.extract(0, param(addA, \A_WIDTH).as_int()) + select nusers(port(addA, \A)) == 2 + //index port(addA, \A) === sigP.extract(0, param(addA, \A_WIDTH).as_int()) // TODO: Why doesn't this work!?! + filter GetSize(port(addA, \A)) <= GetSize(sigP) + filter port(addA, \A) == sigP.extract(0, GetSize(port(addA, \A))) + filter nusers(sigP.extract_end(GetSize(port(addA, \A)))) <= 1 optional endmatch @@ -114,9 +116,10 @@ match addB select addB->type.in($add, $sub) select param(addB, \A_SIGNED).as_bool() && param(addB, \B_SIGNED).as_bool() index nusers(port(addB, \B)) === 2 - //index port(addB, \B) === sigP.extract(0, param(addB, \B_WIDTH).as_int()) - filter param(addB, \B_WIDTH).as_int() <= GetSize(sigP) - filter port(addB, \B) == sigP.extract(0, param(addB, \B_WIDTH).as_int()) + //index port(addB, \B) === sigP.extract(0, param(addB, \B_WIDTH).as_int()) // TODO: Why doesn't this work!?! + filter GetSize(port(addB, \B)) <= GetSize(sigP) + filter port(addB, \B) == sigP.extract(0, GetSize(port(addB, \B))) + filter nusers(sigP.extract_end(GetSize(port(addB, \B)))) <= 1 optional endmatch @@ -135,12 +138,13 @@ code addAB sigC sigP if (!opmodeZ.is_fully_zero()) reject; - int natural_mul_width = GetSize(port(dsp, \A)) + GetSize(port(dsp, \B)); - int actual_mul_width = GetSize(sigP); - int actual_acc_width = GetSize(sigC); + // TODO for DSP48E1, which will have sign extended inputs/outputs + //int natural_mul_width = GetSize(port(dsp, \A)) + GetSize(port(dsp, \B)); + //int actual_mul_width = GetSize(sigP); + //int actual_acc_width = GetSize(sigC); - if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width)) - reject; + //if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width)) + // reject; //if ((actual_acc_width != actual_mul_width) && (param(dsp, \A_SIGNED).as_bool() != param(addAB, \A_SIGNED).as_bool())) // reject; -- cgit v1.2.3 From d2306d7b1d9725fef2d1db4e205c1b0cb6c84715 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 3 Sep 2019 12:18:50 -0700 Subject: Adopt @cliffordwolf's suggestion --- passes/hierarchy/hierarchy.cc | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'passes') diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index ad795c69f..d8a628448 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -808,12 +808,8 @@ struct HierarchyPass : public Pass { if (mod_it.second->get_bool_attribute("\\top")) top_mod = mod_it.second; - if (top_mod != nullptr && auto_top_mode) { - IdString abstract_id = top_mod->name; - IdString top_name = abstract_id; - if (top_name.begins_with("$abstract")) - top_name = top_name.substr(strlen("$abstract")); - top_mod = design->module(top_name); + if (top_mod != nullptr && top_mod->name.begins_with("$abstract")) { + IdString top_name = top_mod->name.substr(strlen("$abstract")); dict top_parameters; for (auto ¶ : parameters) { @@ -823,10 +819,7 @@ struct HierarchyPass : public Pass { top_parameters[RTLIL::escape_id(para.first)] = sig_value.as_const(); } - if (top_mod == nullptr && design->module(abstract_id)) - top_mod = design->module(design->module(abstract_id)->derive(design, top_parameters)); - else if (top_mod != nullptr && !top_parameters.empty()) - top_mod = design->module(top_mod->derive(design, top_parameters)); + top_mod = design->module(top_mod->derive(design, top_parameters)); if (top_mod != nullptr && top_mod->name != top_name) { Module *m = top_mod->clone(); -- cgit v1.2.3 From 97d11708e0104f722578b98ea70a0ba41f9e03cc Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 3 Sep 2019 14:37:32 -0700 Subject: Use feedback path for MACC --- passes/pmgen/xilinx_dsp.cc | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 631b93afa..9307b3d37 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -51,21 +51,6 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) bit_to_driver.insert(std::make_pair(cell->getPort("\\P")[17], cell)); SigSpec P = st.sigP; - if (st.addAB) { - log_assert(st.addAB->getParam("\\A_SIGNED").as_bool()); - log_assert(st.addAB->getParam("\\B_SIGNED").as_bool()); - log(" adder %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); - - SigSpec C = st.sigC; - C.extend_u0(48, true); - cell->setPort("\\C", C); - SigSpec &opmode = cell->connections_.at("\\OPMODE"); - opmode[6] = State::S0; - opmode[5] = State::S1; - opmode[4] = State::S1; - pm.autoremove(st.addAB); - } - if (st.clock != SigBit()) { cell->setPort("\\CLK", st.clock); @@ -140,6 +125,27 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("\n"); } + if (st.addAB) { + log_assert(st.addAB->getParam("\\A_SIGNED").as_bool()); + log_assert(st.addAB->getParam("\\B_SIGNED").as_bool()); + log(" adder %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); + + SigSpec C = st.sigC; + SigSpec &opmode = cell->connections_.at("\\OPMODE"); + if (cell->getParam("\\PREG").as_bool() && C == P) { + opmode[4] = State::S0; + } + else { + C.extend_u0(48, true); + cell->setPort("\\C", C); + opmode[4] = State::S1; + } + opmode[6] = State::S0; + opmode[5] = State::S1; + + pm.autoremove(st.addAB); + } + if (GetSize(P) < 48) P.append(pm.module->addWire(NEW_ID, 48-GetSize(P))); cell->setPort("\\P", P); -- cgit v1.2.3 From 682153de4bb1869187e567a41c22fbed23bcdfd1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 3 Sep 2019 14:57:59 -0700 Subject: Process post-adder first since C could be used for load-P --- passes/pmgen/xilinx_dsp.cc | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 9307b3d37..1732a2d6a 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -49,8 +49,27 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) Cell *cell = st.dsp; bit_to_driver.insert(std::make_pair(cell->getPort("\\P")[17], cell)); + SigSpec C = st.sigC; SigSpec P = st.sigP; + if (st.addAB) { + log_assert(st.addAB->getParam("\\A_SIGNED").as_bool()); + log_assert(st.addAB->getParam("\\B_SIGNED").as_bool()); + log(" adder %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); + + SigSpec &opmode = cell->connections_.at("\\OPMODE"); + if (st.ffP && C == P) { + C = SigSpec(); + opmode[4] = State::S0; + } + else + opmode[4] = State::S1; + opmode[6] = State::S0; + opmode[5] = State::S1; + + pm.autoremove(st.addAB); + } + if (st.clock != SigBit()) { cell->setPort("\\CLK", st.clock); @@ -125,25 +144,10 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("\n"); } - if (st.addAB) { - log_assert(st.addAB->getParam("\\A_SIGNED").as_bool()); - log_assert(st.addAB->getParam("\\B_SIGNED").as_bool()); - log(" adder %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); - - SigSpec C = st.sigC; - SigSpec &opmode = cell->connections_.at("\\OPMODE"); - if (cell->getParam("\\PREG").as_bool() && C == P) { - opmode[4] = State::S0; - } - else { + if (!C.empty()) { + if (GetSize(C) < 48) C.extend_u0(48, true); - cell->setPort("\\C", C); - opmode[4] = State::S1; - } - opmode[6] = State::S0; - opmode[5] = State::S1; - - pm.autoremove(st.addAB); + cell->setPort("\\C", C); } if (GetSize(P) < 48) -- cgit v1.2.3 From 2d80866dafe9e2e2edd2d49e999c1f6a35541852 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 3 Sep 2019 15:53:10 -0700 Subject: Add support for load value into DSP48E1.P --- passes/pmgen/xilinx_dsp.cc | 7 ++++- passes/pmgen/xilinx_dsp.pmg | 70 ++++++++++++++++++++++++++------------------- 2 files changed, 47 insertions(+), 30 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 1732a2d6a..b3d302071 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -40,6 +40,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("dsp: %s\n", log_id(st.dsp, "--")); log("ffM: %s\n", log_id(st.ffM, "--")); log("addAB: %s\n", log_id(st.addAB, "--")); + log("muxAB: %s\n", log_id(st.muxAB, "--")); log("ffP: %s\n", log_id(st.ffP, "--")); //log("muxP: %s\n", log_id(st.muxP, "--")); log("sigPused: %s\n", log_signal(st.sigPused)); @@ -58,7 +59,11 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log(" adder %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); SigSpec &opmode = cell->connections_.at("\\OPMODE"); - if (st.ffP && C == P) { + if (st.ffP && st.muxAB) { + opmode[4] = st.muxAB->getPort("\\S"); + pm.autoremove(st.muxAB); + } + else if (st.ffP && C == P) { C = SigSpec(); opmode[4] = State::S0; } diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 132b09b2b..fdc3fa5e7 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -3,7 +3,7 @@ pattern xilinx_dsp state clock state > sigAset sigBset state sigC sigM sigMused sigP sigPused -state addAB +state addAB muxAB match dsp select dsp->type.in(\DSP48E1) @@ -172,34 +172,7 @@ match ffP optional endmatch -//// $mux cell left behind by dff2dffe -//// would prefer not to run 'opt_expr -mux_undef' -//// since that would lose information helpful for -//// efficient wide-mux inference -//match muxP -// if !sigPused.empty() && !ffP -// select muxP->type.in($mux) -// select nusers(port(muxP, \B)) == 2 -// select port(muxP, \A).is_fully_undef() -// filter param(muxP, \WIDTH).as_int() >= GetSize(sigPused) -// filter includes(port(muxP, \B).to_sigbit_set(), sigPused.to_sigbit_set()) -// optional -//endmatch -// -//match ffY -// if muxP -// select ffY->type.in($dff, $dffe) -// select nusers(port(ffY, \D)) == 2 -// // DSP48E1 does not support clock inversion -// select param(ffY, \CLK_POLARITY).as_bool() -// filter param(ffY, \WIDTH).as_int() >= GetSize(sigPused) -// filter includes(port(ffY, \D).to_sigbit_set(), port(muxP, \Y).to_sigbit_set()) -//endmatch - -code ffP clock -// if (ffY) -// ffP = ffY; - +code ffP sigP clock if (ffP) { for (auto b : port(ffP, \Q)) if (b.wire->get_bool_attribute(\keep)) @@ -211,7 +184,46 @@ code ffP clock reject; clock = c; + + sigP = port(ffP, \Q); + } +endcode + +match muxA + if addAB + select muxA->type.in($mux) + select nusers(port(muxA, \Y)) == 2 + index port(muxA, \A) === sigP + index port(muxA, \Y) === sigC + optional +endmatch + +match muxB + if addAB + select muxB->type.in($mux) + select nusers(port(muxB, \Y)) == 2 + index port(muxB, \B) === sigP + index port(muxB, \Y) === sigC + optional +endmatch + +code sigC muxAB + if (muxA) { + muxAB = muxA; + sigC = port(muxAB, \B); + } + if (muxB) { + muxAB = muxB; + sigC = port(muxAB, \A); } + if (muxAB) { + // Ensure that adder is not used + SigSpec opmodeZ = port(dsp, \OPMODE).extract(4,3); + if (!opmodeZ.is_fully_zero()) + reject; + } +endcode +code accept; endcode -- cgit v1.2.3 From cd002ad3fb20bb98027f29e0c1005bf1df7c432c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 3 Sep 2019 16:10:16 -0700 Subject: Use choices for addAB, now called postAdd --- passes/pmgen/xilinx_dsp.cc | 12 ++++----- passes/pmgen/xilinx_dsp.pmg | 63 +++++++++++++++++---------------------------- 2 files changed, 29 insertions(+), 46 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index b3d302071..7f51d29f6 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -39,7 +39,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("ffB: %s\n", log_id(st.ffB, "--")); log("dsp: %s\n", log_id(st.dsp, "--")); log("ffM: %s\n", log_id(st.ffM, "--")); - log("addAB: %s\n", log_id(st.addAB, "--")); + log("postAdd: %s\n", log_id(st.postAdd, "--")); log("muxAB: %s\n", log_id(st.muxAB, "--")); log("ffP: %s\n", log_id(st.ffP, "--")); //log("muxP: %s\n", log_id(st.muxP, "--")); @@ -53,10 +53,10 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) SigSpec C = st.sigC; SigSpec P = st.sigP; - if (st.addAB) { - log_assert(st.addAB->getParam("\\A_SIGNED").as_bool()); - log_assert(st.addAB->getParam("\\B_SIGNED").as_bool()); - log(" adder %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); + if (st.postAdd) { + log_assert(st.postAdd->getParam("\\A_SIGNED").as_bool()); + log_assert(st.postAdd->getParam("\\B_SIGNED").as_bool()); + log(" adder %s (%s)\n", log_id(st.postAdd), log_id(st.postAdd->type)); SigSpec &opmode = cell->connections_.at("\\OPMODE"); if (st.ffP && st.muxAB) { @@ -72,7 +72,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) opmode[6] = State::S0; opmode[5] = State::S1; - pm.autoremove(st.addAB); + pm.autoremove(st.postAdd); } if (st.clock != SigBit()) diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index fdc3fa5e7..0aafc9e40 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -3,7 +3,8 @@ pattern xilinx_dsp state clock state > sigAset sigBset state sigC sigM sigMused sigP sigPused -state addAB muxAB +state postAdd muxAB +state postAddAB match dsp select dsp->type.in(\DSP48E1) @@ -100,43 +101,25 @@ code clock sigM sigP sigP = sigM; endcode -match addA - select addA->type.in($add) - select param(addA, \A_SIGNED).as_bool() && param(addA, \B_SIGNED).as_bool() - select nusers(port(addA, \A)) == 2 - //index port(addA, \A) === sigP.extract(0, param(addA, \A_WIDTH).as_int()) // TODO: Why doesn't this work!?! - filter GetSize(port(addA, \A)) <= GetSize(sigP) - filter port(addA, \A) == sigP.extract(0, GetSize(port(addA, \A))) - filter nusers(sigP.extract_end(GetSize(port(addA, \A)))) <= 1 +match postAdd + // Ensure that Z mux is not already used + if port(dsp, \OPMODE).extract(4,3).is_fully_zero() + + select postAdd->type.in($postAdd) + select param(postAdd, \A_SIGNED).as_bool() && param(postAdd, \B_SIGNED).as_bool() + choice AB {\A, \B} + define AB_WIDTH (AB == \A ? \A_WIDTH : \B_WIDTH) + select nusers(port(postAdd, AB)) == 2 + filter GetSize(port(postAdd, AB)) <= GetSize(sigP) + filter port(postAdd, AB) == sigP.extract(0, GetSize(port(postAdd, AB))) + filter nusers(sigP.extract_end(GetSize(port(postAdd, AB)))) <= 1 + set postAddAB AB optional endmatch -match addB - if !addA - select addB->type.in($add, $sub) - select param(addB, \A_SIGNED).as_bool() && param(addB, \B_SIGNED).as_bool() - index nusers(port(addB, \B)) === 2 - //index port(addB, \B) === sigP.extract(0, param(addB, \B_WIDTH).as_int()) // TODO: Why doesn't this work!?! - filter GetSize(port(addB, \B)) <= GetSize(sigP) - filter port(addB, \B) == sigP.extract(0, GetSize(port(addB, \B))) - filter nusers(sigP.extract_end(GetSize(port(addB, \B)))) <= 1 - optional -endmatch - -code addAB sigC sigP - if (addA) { - addAB = addA; - sigC = port(addAB, \B); - } - if (addB) { - addAB = addB; - sigC = port(addAB, \A); - } - if (addAB) { - // Ensure that adder is not used - SigSpec opmodeZ = port(dsp, \OPMODE).extract(4,3); - if (!opmodeZ.is_fully_zero()) - reject; +code sigC sigP + if (postAdd) { + sigC = port(postAdd, postAddAB == \A ? \B : \A); // TODO for DSP48E1, which will have sign extended inputs/outputs //int natural_mul_width = GetSize(port(dsp, \A)) + GetSize(port(dsp, \B)); @@ -145,10 +128,10 @@ code addAB sigC sigP //if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width)) // reject; - //if ((actual_acc_width != actual_mul_width) && (param(dsp, \A_SIGNED).as_bool() != param(addAB, \A_SIGNED).as_bool())) + //if ((actual_acc_width != actual_mul_width) && (param(dsp, \A_SIGNED).as_bool() != param(postAdd, \A_SIGNED).as_bool())) // reject; - sigP = port(addAB, \Y); + sigP = port(postAdd, \Y); } endcode @@ -190,7 +173,7 @@ code ffP sigP clock endcode match muxA - if addAB + if postAdd select muxA->type.in($mux) select nusers(port(muxA, \Y)) == 2 index port(muxA, \A) === sigP @@ -199,7 +182,7 @@ match muxA endmatch match muxB - if addAB + if postAdd select muxB->type.in($mux) select nusers(port(muxB, \Y)) == 2 index port(muxB, \B) === sigP @@ -217,7 +200,7 @@ code sigC muxAB sigC = port(muxAB, \A); } if (muxAB) { - // Ensure that adder is not used + // Ensure that postAdder is not used SigSpec opmodeZ = port(dsp, \OPMODE).extract(4,3); if (!opmodeZ.is_fully_zero()) reject; -- cgit v1.2.3 From 16316aa05d548c79fa1580defe71097efdeb78b9 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 3 Sep 2019 16:24:59 -0700 Subject: Rename muxAB to postAddMux --- passes/pmgen/xilinx_dsp.cc | 22 ++++++++++----------- passes/pmgen/xilinx_dsp.pmg | 47 ++++++++++++++------------------------------- 2 files changed, 25 insertions(+), 44 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 7f51d29f6..17e05c39c 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -35,15 +35,15 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) #if 1 log("\n"); - log("ffA: %s\n", log_id(st.ffA, "--")); - log("ffB: %s\n", log_id(st.ffB, "--")); - log("dsp: %s\n", log_id(st.dsp, "--")); - log("ffM: %s\n", log_id(st.ffM, "--")); - log("postAdd: %s\n", log_id(st.postAdd, "--")); - log("muxAB: %s\n", log_id(st.muxAB, "--")); - log("ffP: %s\n", log_id(st.ffP, "--")); + log("ffA: %s\n", log_id(st.ffA, "--")); + log("ffB: %s\n", log_id(st.ffB, "--")); + log("dsp: %s\n", log_id(st.dsp, "--")); + log("ffM: %s\n", log_id(st.ffM, "--")); + log("postAdd: %s\n", log_id(st.postAdd, "--")); + log("postAddMux: %s\n", log_id(st.postAddMux, "--")); + log("ffP: %s\n", log_id(st.ffP, "--")); //log("muxP: %s\n", log_id(st.muxP, "--")); - log("sigPused: %s\n", log_signal(st.sigPused)); + log("sigPused: %s\n", log_signal(st.sigPused)); #endif log("Analysing %s.%s for Xilinx DSP packing.\n", log_id(pm.module), log_id(st.dsp)); @@ -59,9 +59,9 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log(" adder %s (%s)\n", log_id(st.postAdd), log_id(st.postAdd->type)); SigSpec &opmode = cell->connections_.at("\\OPMODE"); - if (st.ffP && st.muxAB) { - opmode[4] = st.muxAB->getPort("\\S"); - pm.autoremove(st.muxAB); + if (st.ffP && st.postAddMux) { + opmode[4] = st.postAddMux->getPort("\\S"); + pm.autoremove(st.postAddMux); } else if (st.ffP && C == P) { C = SigSpec(); diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 0aafc9e40..8c8f431a4 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -3,8 +3,8 @@ pattern xilinx_dsp state clock state > sigAset sigBset state sigC sigM sigMused sigP sigPused -state postAdd muxAB -state postAddAB +state postAdd postAddMux +state postAddAB postAddMuxAB match dsp select dsp->type.in(\DSP48E1) @@ -105,10 +105,9 @@ match postAdd // Ensure that Z mux is not already used if port(dsp, \OPMODE).extract(4,3).is_fully_zero() - select postAdd->type.in($postAdd) + select postAdd->type.in($add) select param(postAdd, \A_SIGNED).as_bool() && param(postAdd, \B_SIGNED).as_bool() choice AB {\A, \B} - define AB_WIDTH (AB == \A ? \A_WIDTH : \B_WIDTH) select nusers(port(postAdd, AB)) == 2 filter GetSize(port(postAdd, AB)) <= GetSize(sigP) filter port(postAdd, AB) == sigP.extract(0, GetSize(port(postAdd, AB))) @@ -172,39 +171,21 @@ code ffP sigP clock } endcode -match muxA +match postAddMux if postAdd - select muxA->type.in($mux) - select nusers(port(muxA, \Y)) == 2 - index port(muxA, \A) === sigP - index port(muxA, \Y) === sigC - optional -endmatch - -match muxB - if postAdd - select muxB->type.in($mux) - select nusers(port(muxB, \Y)) == 2 - index port(muxB, \B) === sigP - index port(muxB, \Y) === sigC + if ffP + select postAddMux->type.in($mux) + select nusers(port(postAddMux, \Y)) == 2 + choice AB {\A, \B} + index port(postAddMux, AB) === sigP + index port(postAddMux, \Y) === sigC + set postAddMuxAB AB optional endmatch -code sigC muxAB - if (muxA) { - muxAB = muxA; - sigC = port(muxAB, \B); - } - if (muxB) { - muxAB = muxB; - sigC = port(muxAB, \A); - } - if (muxAB) { - // Ensure that postAdder is not used - SigSpec opmodeZ = port(dsp, \OPMODE).extract(4,3); - if (!opmodeZ.is_fully_zero()) - reject; - } +code sigC + if (postAddMux) + sigC = port(postAddMux, postAddMuxAB == \A ? \B : \A); endcode code -- cgit v1.2.3 From 80aec0f006b91b0163c8be94f2450223e6e97a52 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 3 Sep 2019 16:37:59 -0700 Subject: st.ffP from if to assert --- passes/pmgen/xilinx_dsp.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 17e05c39c..95105275b 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -59,7 +59,8 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log(" adder %s (%s)\n", log_id(st.postAdd), log_id(st.postAdd->type)); SigSpec &opmode = cell->connections_.at("\\OPMODE"); - if (st.ffP && st.postAddMux) { + if (st.postAddMux) { + log_assert(st.ffP); opmode[4] = st.postAddMux->getPort("\\S"); pm.autoremove(st.postAddMux); } -- cgit v1.2.3 From e67e4a5ed66df59f5f924e6bb3891f87fc93f070 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 4 Sep 2019 10:52:51 -0700 Subject: Support CEM --- passes/pmgen/xilinx_dsp.cc | 10 ++++++---- passes/pmgen/xilinx_dsp.pmg | 32 +++++++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 9 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 95105275b..4d2152f61 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -39,6 +39,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("ffB: %s\n", log_id(st.ffB, "--")); log("dsp: %s\n", log_id(st.dsp, "--")); log("ffM: %s\n", log_id(st.ffM, "--")); + log("ffMmux: %s\n", log_id(st.ffMmux, "--")); log("postAdd: %s\n", log_id(st.postAdd, "--")); log("postAddMux: %s\n", log_id(st.postAddMux, "--")); log("ffP: %s\n", log_id(st.ffP, "--")); @@ -111,11 +112,12 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) SigSpec Q = st.ffM->getPort("\\Q"); P.replace(pm.sigmap(D), Q); cell->setParam("\\MREG", State::S1); - if (st.ffM->type == "$dff") + if (st.ffMmux) { + cell->setPort("\\CEM", st.ffMmux->getPort("\\S")); + pm.autoremove(st.ffMmux); + } + else cell->setPort("\\CEM", State::S1); - //else if (st.ffP->type == "$dffe") - // cell->setPort("\\CEM", st.ffM->getPort("\\EN")); - else log_abort(); pm.autoremove(st.ffM); } if (st.ffP) { diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 8c8f431a4..9b01c22ee 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -2,9 +2,8 @@ pattern xilinx_dsp state clock state > sigAset sigBset -state sigC sigM sigMused sigP sigPused -state postAdd postAddMux -state postAddAB postAddMuxAB +state sigC sigM sigP sigPused +state ffMmuxAB postAddAB postAddMuxAB match dsp select dsp->type.in(\DSP48E1) @@ -70,22 +69,40 @@ code clock } endcode +match ffMmux + select ffMmux->type.in($mux) + select nusers(port(ffMmux, \Y)) == 2 + filter GetSize(port(ffMmux, \Y)) <= GetSize(sigM) + choice AB {\A, \B} + filter port(ffMmux, AB) == sigM.extract(0, GetSize(port(ffMmux, \Y))) + filter nusers(sigM.extract_end(GetSize(port(ffMmux, AB)))) <= 1 + set ffMmuxAB AB + optional +endmatch + +code sigM + if (ffMmux) + sigM = port(ffMmux, \Y); +endcode + match ffM if param(dsp, \MREG).as_int() == 0 select ffM->type.in($dff) // DSP48E1 does not support clock inversion select param(ffM, \CLK_POLARITY).as_bool() select nusers(port(ffM, \D)) == 2 - //index port(ffM, \D) === sigM.extract(0, GetSize(port(ffM, \D))) // TODO: Why doesn't this work!?! filter GetSize(port(ffM, \D)) <= GetSize(sigM) filter port(ffM, \D) == sigM.extract(0, GetSize(port(ffM, \D))) filter nusers(sigM.extract_end(GetSize(port(ffM, \D)))) <= 1 + // Check ffMmux (when present) is a $dff enable mux + filter !ffMmux || port(ffM, \Q) == port(ffMmux, ffMmuxAB == \A ? \B : \A) optional endmatch code clock sigM sigP if (ffM) { sigM = port(ffM, \Q); + for (auto b : sigM) if (b.wire->get_bool_attribute(\keep)) reject; @@ -97,6 +114,9 @@ code clock sigM sigP clock = c; } + // Cannot have ffMmux enable mux without ffM + else if (ffMmux) + reject; sigP = sigM; endcode @@ -108,7 +128,9 @@ match postAdd select postAdd->type.in($add) select param(postAdd, \A_SIGNED).as_bool() && param(postAdd, \B_SIGNED).as_bool() choice AB {\A, \B} - select nusers(port(postAdd, AB)) == 2 + select nusers(port(postAdd, AB)) <= 3 + filter ffMmux || nusers(port(postAdd, AB)) == 2 + filter !ffMmux || nusers(port(postAdd, AB)) == 3 filter GetSize(port(postAdd, AB)) <= GetSize(sigP) filter port(postAdd, AB) == sigP.extract(0, GetSize(port(postAdd, AB))) filter nusers(sigP.extract_end(GetSize(port(postAdd, AB)))) <= 1 -- cgit v1.2.3 From 2b86055848c396591c6ec693a8abd8826b300b2b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 4 Sep 2019 12:35:15 -0700 Subject: Add peepopt_dffmuxext --- passes/pmgen/Makefile.inc | 1 + passes/pmgen/peepopt.cc | 1 + passes/pmgen/peepopt_dffmuxext.pmg | 58 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 passes/pmgen/peepopt_dffmuxext.pmg (limited to 'passes') diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index 4989c582a..6648e2ec0 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -27,6 +27,7 @@ $(eval $(call add_extra_objs,passes/pmgen/peepopt_pm.h)) PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul.pmg PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg +PEEPOPT_PATTERN += passes/pmgen/peepopt_dffmuxext.pmg passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN) $(P) mkdir -p passes/pmgen && python3 $< -o $@ -p peepopt $(filter-out $<,$^) diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index e7f95cf85..b57d26cef 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -60,6 +60,7 @@ struct PeepoptPass : public Pass { peepopt_pm pm(module, module->selected_cells()); pm.run_shiftmul(); pm.run_muldiv(); + pm.run_dffmuxext(); } } } diff --git a/passes/pmgen/peepopt_dffmuxext.pmg b/passes/pmgen/peepopt_dffmuxext.pmg new file mode 100644 index 000000000..e99ce1602 --- /dev/null +++ b/passes/pmgen/peepopt_dffmuxext.pmg @@ -0,0 +1,58 @@ +pattern dffmuxext + +state muxAB + +match dff + select dff->type == $dff + select GetSize(port(dff, \D)) > 1 +endmatch + +match mux + select mux->type == $mux + select GetSize(port(mux, \Y)) > 1 + choice AB {\A, \B} + //select port(mux, AB)[GetSize(port(mux, \Y))-1].wire + index port(mux, \Y) === port(dff, \D) + define BA (AB == \A ? \B : \A) + index port(mux, BA) === port(dff, \Q) + filter port(mux, AB)[GetSize(port(mux, \Y))-1] == port(mux, AB)[GetSize(port(mux, \Y))-2] + set muxAB AB +endmatch + +code + did_something = true; + + log_cell(dff); + log_cell(mux); + + SigSpec &D = mux->connections_.at(muxAB); + SigSpec &Q = dff->connections_.at(\Q); + int width = GetSize(D); + + SigBit sign = D[width-1]; + bool is_signed = sign.wire; + int i; + for (i = width-1; i >= 2; i--) { + if (!is_signed) { + module->connect(Q[i], sign); + if (D[i-1] != sign) + break; + } + else { + module->connect(Q[i], Q[i-1]); + if (D[i-2] != sign) + break; + } + } + + mux->connections_.at(\A).remove(i, width-i); + mux->connections_.at(\B).remove(i, width-i); + mux->connections_.at(\Y).remove(i, width-i); + mux->fixup_parameters(); + dff->connections_.at(\D).remove(i, width-i); + dff->connections_.at(\Q).remove(i, width-i); + dff->fixup_parameters(); + + log("dffmuxext pattern in %s: dff=%s, mux=%s; removed top %d bits.\n", log_id(module), log_id(dff), log_id(mux), width-i); + accept; +endcode -- cgit v1.2.3 From 433b0c677c16ef5cc2fa92c576c54cc1a3a09f7f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 4 Sep 2019 13:42:44 -0700 Subject: Remove log_cell() calls --- passes/pmgen/peepopt_dffmuxext.pmg | 3 --- 1 file changed, 3 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/peepopt_dffmuxext.pmg b/passes/pmgen/peepopt_dffmuxext.pmg index e99ce1602..2465d6171 100644 --- a/passes/pmgen/peepopt_dffmuxext.pmg +++ b/passes/pmgen/peepopt_dffmuxext.pmg @@ -22,9 +22,6 @@ endmatch code did_something = true; - log_cell(dff); - log_cell(mux); - SigSpec &D = mux->connections_.at(muxAB); SigSpec &Q = dff->connections_.at(\Q); int width = GetSize(D); -- cgit v1.2.3 From 93d798272d027f15aa930766bc3f9553f448f5cf Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 4 Sep 2019 16:59:57 -0700 Subject: Compute sigP properly --- passes/pmgen/xilinx_dsp.pmg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 9b01c22ee..c45e92d6f 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -189,7 +189,7 @@ code ffP sigP clock clock = c; - sigP = port(ffP, \Q); + sigP.replace(port(ffP, \D), port(ffP, \Q)); } endcode -- cgit v1.2.3 From 42548d979018c4bc3b71d4faa0900b18d2d290ec Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 4 Sep 2019 17:06:17 -0700 Subject: Get rid of sigPused --- passes/pmgen/xilinx_dsp.cc | 2 -- passes/pmgen/xilinx_dsp.pmg | 27 +++++++++++++-------------- 2 files changed, 13 insertions(+), 16 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 4d2152f61..0d1937844 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -43,8 +43,6 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("postAdd: %s\n", log_id(st.postAdd, "--")); log("postAddMux: %s\n", log_id(st.postAddMux, "--")); log("ffP: %s\n", log_id(st.ffP, "--")); - //log("muxP: %s\n", log_id(st.muxP, "--")); - log("sigPused: %s\n", log_signal(st.sigPused)); #endif log("Analysing %s.%s for Xilinx DSP packing.\n", log_id(pm.module), log_id(st.dsp)); diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index c45e92d6f..375b5a492 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -19,8 +19,16 @@ code sigAset sigBset endcode code sigM - sigM = port(dsp, \P); - //if (GetSize(sigH) <= 10) + SigSpec P = port(dsp, \P); + // Only care about those bits that are used + int i; + for (i = 0; i < GetSize(P); i++) { + if (nusers(P[i]) <= 1) + break; + sigM.append(P[i]); + } + log_assert(nusers(P.extract_end(i)) <= 1); + //if (GetSize(sigM) <= 10) // reject; endcode @@ -156,23 +164,14 @@ code sigC sigP } endcode -// Extract the bits of P that actually have a consumer -// (as opposed to being a dummy) -code sigPused - for (int i = 0; i < GetSize(sigP); i++) - if (sigP[i].wire && nusers(sigP[i]) > 1) - sigPused.append(sigP[i]); -endcode - match ffP if param(dsp, \PREG).as_int() == 0 - if !sigPused.empty() - if nusers(sigPused) == 2 select ffP->type.in($dff) // DSP48E1 does not support clock inversion select param(ffP, \CLK_POLARITY).as_bool() - filter param(ffP, \WIDTH).as_int() >= GetSize(sigPused) - filter includes(port(ffP, \D).to_sigbit_set(), sigPused.to_sigbit_set()) + filter GetSize(port(ffP, \D)) >= GetSize(sigP) + slice offset GetSize(port(ffP, \D)) + filter offset+GetSize(sigP) <= GetSize(port(ffP, \D)) && port(ffP, \D).extract(offset, GetSize(sigP)) == sigP optional endmatch -- cgit v1.2.3 From 91ef4457b08e15da6b8af9522da002b76feefd06 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 4 Sep 2019 17:18:49 -0700 Subject: Get rid of sigAset --- passes/pmgen/xilinx_dsp.pmg | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 375b5a492..598276063 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,18 +1,21 @@ pattern xilinx_dsp state clock -state > sigAset sigBset -state sigC sigM sigP sigPused +state > sigBset +state sigA sigC sigM sigP sigPused state ffMmuxAB postAddAB postAddMuxAB match dsp select dsp->type.in(\DSP48E1) endmatch -code sigAset sigBset - SigSpec A = port(dsp, \A); - A.remove_const(); - sigAset = A.to_sigbit_set(); +code sigA sigBset + sigA = port(dsp, \A); + int i; + for (i = GetSize(sigA)-1; i > 0; i--) + if (sigA[i] != sigA[i-1]) + break; + sigA.remove(i, GetSize(sigA)-i); SigSpec B = port(dsp, \B); B.remove_const(); sigBset = B.to_sigbit_set(); @@ -34,21 +37,22 @@ endcode match ffA if param(dsp, \AREG).as_int() == 0 - if !sigAset.empty() select ffA->type.in($dff) // DSP48E1 does not support clock inversion select param(ffA, \CLK_POLARITY).as_bool() - filter includes(port(ffA, \Q).to_sigbit_set(), sigAset) + filter GetSize(port(ffA, \Q)) >= GetSize(sigA) + slice offset GetSize(port(ffA, \Q)) + filter offset+GetSize(sigA) <= GetSize(port(ffA, \Q)) && port(ffA, \Q).extract(offset, GetSize(sigA)) == sigA optional endmatch code clock if (ffA) { - clock = port(ffA, \CLK).as_bit(); - for (auto b : port(ffA, \Q)) if (b.wire->get_bool_attribute(\keep)) reject; + + clock = port(ffA, \CLK).as_bit(); } endcode -- cgit v1.2.3 From 09c26c55bb4357f0b7204d8a78806aa7ad12068f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 4 Sep 2019 17:22:02 -0700 Subject: Get rid of sigBset too --- passes/pmgen/xilinx_dsp.cc | 4 ---- passes/pmgen/xilinx_dsp.pmg | 18 ++++++++++-------- 2 files changed, 10 insertions(+), 12 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 0d1937844..c742ef84d 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -23,10 +23,6 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -template inline bool includes(const T &lhs, const T &rhs) { - return std::includes(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); -} -#include #include "passes/pmgen/xilinx_dsp_pm.h" void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 598276063..d37792b29 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,24 +1,25 @@ pattern xilinx_dsp state clock -state > sigBset -state sigA sigC sigM sigP sigPused +state sigA sigB sigC sigM sigP sigPused state ffMmuxAB postAddAB postAddMuxAB match dsp select dsp->type.in(\DSP48E1) endmatch -code sigA sigBset +code sigA sigB sigA = port(dsp, \A); int i; for (i = GetSize(sigA)-1; i > 0; i--) if (sigA[i] != sigA[i-1]) break; sigA.remove(i, GetSize(sigA)-i); - SigSpec B = port(dsp, \B); - B.remove_const(); - sigBset = B.to_sigbit_set(); + sigB = port(dsp, \B); + for (i = GetSize(sigB)-1; i > 0; i--) + if (sigB[i] != sigB[i-1]) + break; + sigB.remove(i, GetSize(sigB)-i); endcode code sigM @@ -58,11 +59,12 @@ endcode match ffB if param(dsp, \BREG).as_int() == 0 - if !sigBset.empty() select ffB->type.in($dff) // DSP48E1 does not support clock inversion select param(ffB, \CLK_POLARITY).as_bool() - filter includes(port(ffB, \Q).to_sigbit_set(), sigBset) + filter GetSize(port(ffB, \Q)) >= GetSize(sigB) + slice offset GetSize(port(ffB, \Q)) + filter offset+GetSize(sigB) <= GetSize(port(ffB, \Q)) && port(ffB, \Q).extract(offset, GetSize(sigB)) == sigB optional endmatch -- cgit v1.2.3 From 694a8f75cf7a8bcf86a421ca6c9fe3560b1e2a0f Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 27 Aug 2019 00:55:43 +0200 Subject: Add flatten handling of pre-existing wires as created by interfaces, fixes #1145 Signed-off-by: Clifford Wolf --- passes/techmap/techmap.cc | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'passes') diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index c4496f76f..cb01cadb1 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -211,14 +211,26 @@ struct TechmapWorker positional_ports[stringf("$%d", it.second->port_id)] = it.first; IdString w_name = it.second->name; apply_prefix(cell->name, w_name); - RTLIL::Wire *w = module->addWire(w_name, it.second); - w->port_input = false; - w->port_output = false; - w->port_id = 0; - if (it.second->get_bool_attribute(ID(_techmap_special_))) - w->attributes.clear(); - if (w->attributes.count(ID(src))) - w->add_strpool_attribute(ID(src), extra_src_attrs); + RTLIL::Wire *w = module->wire(w_name); + if (w != nullptr) { + if (!flatten_mode) + log_error("Signal %s.%s conflicts with %s.%s (via %s.%s).\n", log_id(module), log_id(w), + log_id(tpl), log_id(it.second), log_id(module), log_id(cell)); + if (GetSize(w) < GetSize(it.second)) { + log_warning("Widening signal %s.%s to match size of %s.%s (via %s.%s).\n", log_id(module), log_id(w), + log_id(tpl), log_id(it.second), log_id(module), log_id(cell)); + w->width = GetSize(it.second); + } + } else { + w = module->addWire(w_name, it.second); + w->port_input = false; + w->port_output = false; + w->port_id = 0; + if (it.second->get_bool_attribute(ID(_techmap_special_))) + w->attributes.clear(); + if (w->attributes.count(ID(src))) + w->add_strpool_attribute(ID(src), extra_src_attrs); + } design->select(module, w); } -- cgit v1.2.3 From 30f1ac7ce9c44ac5cbd4ad7e389264246a1e3306 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 5 Sep 2019 13:51:53 +0200 Subject: Rename conflicting wires on flatten/techmap, add "hierconn" attribute, fixes #1220 Signed-off-by: Clifford Wolf --- passes/techmap/techmap.cc | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) (limited to 'passes') diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index cb01cadb1..5ce1bf7d6 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -205,6 +205,7 @@ struct TechmapWorker } std::map positional_ports; + dict temp_renamed_wires; for (auto &it : tpl->wires_) { if (it.second->port_id > 0) @@ -213,15 +214,20 @@ struct TechmapWorker apply_prefix(cell->name, w_name); RTLIL::Wire *w = module->wire(w_name); if (w != nullptr) { - if (!flatten_mode) - log_error("Signal %s.%s conflicts with %s.%s (via %s.%s).\n", log_id(module), log_id(w), - log_id(tpl), log_id(it.second), log_id(module), log_id(cell)); - if (GetSize(w) < GetSize(it.second)) { - log_warning("Widening signal %s.%s to match size of %s.%s (via %s.%s).\n", log_id(module), log_id(w), - log_id(tpl), log_id(it.second), log_id(module), log_id(cell)); - w->width = GetSize(it.second); + if (!flatten_mode || !w->get_bool_attribute(ID(hierconn))) { + temp_renamed_wires[w] = w->name; + module->rename(w, NEW_ID); + w = nullptr; + } else { + w->attributes.erase(ID(hierconn)); + if (GetSize(w) < GetSize(it.second)) { + log_warning("Widening signal %s.%s to match size of %s.%s (via %s.%s).\n", log_id(module), log_id(w), + log_id(tpl), log_id(it.second), log_id(module), log_id(cell)); + w->width = GetSize(it.second); + } } - } else { + } + if (w == nullptr) { w = module->addWire(w_name, it.second); w->port_input = false; w->port_output = false; @@ -392,6 +398,16 @@ struct TechmapWorker } module->remove(cell); + + for (auto &it : temp_renamed_wires) + { + Wire *w = it.first; + IdString name = it.second; + IdString altname = module->uniquify(name); + Wire *other_w = module->wire(name); + module->rename(other_w, altname); + module->rename(w, name); + } } bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, std::set &handled_cells, -- cgit v1.2.3 From aa462da39513505a66840dca49a5f4499531d952 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 5 Sep 2019 10:07:26 -0700 Subject: Support CEA --- passes/pmgen/xilinx_dsp.cc | 17 +++++++++++------ passes/pmgen/xilinx_dsp.pmg | 26 +++++++++++++++++++++++--- 2 files changed, 34 insertions(+), 9 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index c742ef84d..2f36a5bde 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -32,6 +32,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) #if 1 log("\n"); log("ffA: %s\n", log_id(st.ffA, "--")); + log("ffAmux: %s\n", log_id(st.ffAmux, "--")); log("ffB: %s\n", log_id(st.ffB, "--")); log("dsp: %s\n", log_id(st.dsp, "--")); log("ffM: %s\n", log_id(st.ffM, "--")); @@ -78,15 +79,19 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) if (st.ffA) { SigSpec A = cell->getPort("\\A"); SigSpec D = st.ffA->getPort("\\D"); - SigSpec Q = st.ffA->getPort("\\Q"); + SigSpec Q = pm.sigmap(st.ffA->getPort("\\Q")); A.replace(Q, D); - cell->setPort("\\A", A); + cell->setParam("\\AREG", 1); - if (st.ffA->type == "$dff") + if (st.ffAmux) { + SigSpec Y = st.ffAmux->getPort("\\Y"); + SigSpec AB = st.ffAmux->getPort(st.ffAmuxAB == "\\A" ? "\\B" : "\\A"); + A.replace(Y, AB); + cell->setPort("\\CEA2", st.ffAmux->getPort("\\S")); + } + else cell->setPort("\\CEA2", State::S1); - //else if (st.ffA->type == "$dffe") - // cell->setPort("\\CEA2", st.ffA->getPort("\\EN")); - else log_abort(); + cell->setPort("\\A", A); } if (st.ffB) { SigSpec B = cell->getPort("\\B"); diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index d37792b29..339ac646c 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,8 +1,8 @@ pattern xilinx_dsp state clock -state sigA sigB sigC sigM sigP sigPused -state ffMmuxAB postAddAB postAddMuxAB +state sigA sigffAmux sigB sigC sigM sigP sigPused +state ffAmuxAB ffMmuxAB postAddAB postAddMuxAB match dsp select dsp->type.in(\DSP48E1) @@ -14,11 +14,17 @@ code sigA sigB for (i = GetSize(sigA)-1; i > 0; i--) if (sigA[i] != sigA[i-1]) break; + // Do not remove non-const sign bit + if (sigA[i].wire) + ++i; sigA.remove(i, GetSize(sigA)-i); sigB = port(dsp, \B); for (i = GetSize(sigB)-1; i > 0; i--) if (sigB[i] != sigB[i-1]) break; + // Do not remove non-const sign bit + if (sigB[i].wire) + ++i; sigB.remove(i, GetSize(sigB)-i); endcode @@ -43,20 +49,34 @@ match ffA select param(ffA, \CLK_POLARITY).as_bool() filter GetSize(port(ffA, \Q)) >= GetSize(sigA) slice offset GetSize(port(ffA, \Q)) + filter offset+GetSize(sigA) <= GetSize(port(ffA, \Q)) && nusers(port(ffA, \Q).extract(offset, GetSize(sigA))) <= 3 filter offset+GetSize(sigA) <= GetSize(port(ffA, \Q)) && port(ffA, \Q).extract(offset, GetSize(sigA)) == sigA optional endmatch -code clock +code sigA sigffAmux clock if (ffA) { for (auto b : port(ffA, \Q)) if (b.wire->get_bool_attribute(\keep)) reject; clock = port(ffA, \CLK).as_bit(); + + if (nusers(sigA) == 3) + sigffAmux = sigA; + sigA.replace(port(ffA, \Q), port(ffA, \D)); } endcode +match ffAmux + if sigffAmux != SigSpec() + select ffAmux->type.in($mux) + choice AB {\A, \B} + index port(ffAmux, \Y) === sigA + index port(ffAmux, AB) === sigffAmux + set ffAmuxAB AB +endmatch + match ffB if param(dsp, \BREG).as_int() == 0 select ffB->type.in($dff) -- cgit v1.2.3 From 0166e02e781080f346b37dcb3ba6f9fa947ca22d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 5 Sep 2019 10:07:56 -0700 Subject: Cleanup --- passes/pmgen/xilinx_dsp.pmg | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 339ac646c..ed5bd3aae 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,14 +1,14 @@ pattern xilinx_dsp state clock -state sigA sigffAmux sigB sigC sigM sigP sigPused +state sigA sigffAmux sigB sigC sigM sigP state ffAmuxAB ffMmuxAB postAddAB postAddMuxAB match dsp select dsp->type.in(\DSP48E1) endmatch -code sigA sigB +code sigA sigffAmux sigB sigM sigA = port(dsp, \A); int i; for (i = GetSize(sigA)-1; i > 0; i--) @@ -26,12 +26,9 @@ code sigA sigB if (sigB[i].wire) ++i; sigB.remove(i, GetSize(sigB)-i); -endcode -code sigM SigSpec P = port(dsp, \P); // Only care about those bits that are used - int i; for (i = 0; i < GetSize(P); i++) { if (nusers(P[i]) <= 1) break; -- cgit v1.2.3 From 05282afc2503d1dba1da561c7fbf86ac6cf97466 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 5 Sep 2019 10:46:33 -0700 Subject: Add support for CEB, remove check on nusers --- passes/pmgen/xilinx_dsp.cc | 19 ++++++++++++------- passes/pmgen/xilinx_dsp.pmg | 28 ++++++++++++++++++++-------- 2 files changed, 32 insertions(+), 15 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 2f36a5bde..5ae34a1f7 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -34,6 +34,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("ffA: %s\n", log_id(st.ffA, "--")); log("ffAmux: %s\n", log_id(st.ffAmux, "--")); log("ffB: %s\n", log_id(st.ffB, "--")); + log("ffBmux: %s\n", log_id(st.ffBmux, "--")); log("dsp: %s\n", log_id(st.dsp, "--")); log("ffM: %s\n", log_id(st.ffM, "--")); log("ffMmux: %s\n", log_id(st.ffMmux, "--")); @@ -81,8 +82,6 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) SigSpec D = st.ffA->getPort("\\D"); SigSpec Q = pm.sigmap(st.ffA->getPort("\\Q")); A.replace(Q, D); - - cell->setParam("\\AREG", 1); if (st.ffAmux) { SigSpec Y = st.ffAmux->getPort("\\Y"); SigSpec AB = st.ffAmux->getPort(st.ffAmuxAB == "\\A" ? "\\B" : "\\A"); @@ -92,19 +91,25 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) else cell->setPort("\\CEA2", State::S1); cell->setPort("\\A", A); + + cell->setParam("\\AREG", 1); } if (st.ffB) { SigSpec B = cell->getPort("\\B"); SigSpec D = st.ffB->getPort("\\D"); SigSpec Q = st.ffB->getPort("\\Q"); B.replace(Q, D); + if (st.ffBmux) { + SigSpec Y = st.ffBmux->getPort("\\Y"); + SigSpec AB = st.ffBmux->getPort(st.ffBmuxAB == "\\A" ? "\\B" : "\\A"); + B.replace(Y, AB); + cell->setPort("\\CEB2", st.ffBmux->getPort("\\S")); + } + else + cell->setPort("\\CEB2", State::S1); cell->setPort("\\B", B); + cell->setParam("\\BREG", 1); - if (st.ffB->type == "$dff") - cell->setPort("\\CEB2", State::S1); - //else if (st.ffB->type == "$dffe") - // cell->setPort("\\CEB2", st.ffB->getPort("\\EN")); - else log_abort(); } if (st.ffM) { SigSpec D = st.ffM->getPort("\\D"); diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index ed5bd3aae..2681cdbca 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,14 +1,14 @@ pattern xilinx_dsp state clock -state sigA sigffAmux sigB sigC sigM sigP -state ffAmuxAB ffMmuxAB postAddAB postAddMuxAB +state sigA sigffAmux sigB sigffBmux sigC sigM sigP +state ffAmuxAB ffBmuxAB ffMmuxAB postAddAB postAddMuxAB match dsp select dsp->type.in(\DSP48E1) endmatch -code sigA sigffAmux sigB sigM +code sigA sigffAmux sigB sigffBmux sigM sigA = port(dsp, \A); int i; for (i = GetSize(sigA)-1; i > 0; i--) @@ -46,7 +46,6 @@ match ffA select param(ffA, \CLK_POLARITY).as_bool() filter GetSize(port(ffA, \Q)) >= GetSize(sigA) slice offset GetSize(port(ffA, \Q)) - filter offset+GetSize(sigA) <= GetSize(port(ffA, \Q)) && nusers(port(ffA, \Q).extract(offset, GetSize(sigA))) <= 3 filter offset+GetSize(sigA) <= GetSize(port(ffA, \Q)) && port(ffA, \Q).extract(offset, GetSize(sigA)) == sigA optional endmatch @@ -59,19 +58,19 @@ code sigA sigffAmux clock clock = port(ffA, \CLK).as_bit(); - if (nusers(sigA) == 3) - sigffAmux = sigA; + sigffAmux = sigA; sigA.replace(port(ffA, \Q), port(ffA, \D)); } endcode match ffAmux - if sigffAmux != SigSpec() + if ffA select ffAmux->type.in($mux) choice AB {\A, \B} index port(ffAmux, \Y) === sigA index port(ffAmux, AB) === sigffAmux set ffAmuxAB AB + semioptional endmatch match ffB @@ -85,7 +84,7 @@ match ffB optional endmatch -code clock +code sigB sigffBmux clock if (ffB) { for (auto b : port(ffB, \Q)) if (b.wire->get_bool_attribute(\keep)) @@ -97,9 +96,22 @@ code clock reject; clock = c; + + sigffBmux = sigB; + sigB.replace(port(ffB, \Q), port(ffB, \D)); } endcode +match ffBmux + if ffB + select ffBmux->type.in($mux) + choice AB {\A, \B} + index port(ffBmux, \Y) === sigB + index port(ffBmux, AB) === sigffBmux + set ffBmuxAB AB + semioptional +endmatch + match ffMmux select ffMmux->type.in($mux) select nusers(port(ffMmux, \Y)) == 2 -- cgit v1.2.3 From 447a31e75d7bd77c0108eb0c76b9749340b10db4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 5 Sep 2019 11:00:27 -0700 Subject: Add support for CEP --- passes/pmgen/xilinx_dsp.cc | 33 ++++++++++++++++----------------- passes/pmgen/xilinx_dsp.pmg | 22 ++++++++++++++++++++-- 2 files changed, 36 insertions(+), 19 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 5ae34a1f7..a497d0a48 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -41,6 +41,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("postAdd: %s\n", log_id(st.postAdd, "--")); log("postAddMux: %s\n", log_id(st.postAddMux, "--")); log("ffP: %s\n", log_id(st.ffP, "--")); + log("ffPmux: %s\n", log_id(st.ffPmux, "--")); #endif log("Analysing %s.%s for Xilinx DSP packing.\n", log_id(pm.module), log_id(st.dsp)); @@ -112,34 +113,32 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) cell->setParam("\\BREG", 1); } if (st.ffM) { - SigSpec D = st.ffM->getPort("\\D"); - SigSpec Q = st.ffM->getPort("\\Q"); - P.replace(pm.sigmap(D), Q); - cell->setParam("\\MREG", State::S1); if (st.ffMmux) { cell->setPort("\\CEM", st.ffMmux->getPort("\\S")); pm.autoremove(st.ffMmux); } else cell->setPort("\\CEM", State::S1); + SigSpec D = st.ffM->getPort("\\D"); + SigSpec Q = st.ffM->getPort("\\Q"); + P.replace(/*pm.sigmap*/(D), Q); + + cell->setParam("\\MREG", State::S1); pm.autoremove(st.ffM); } if (st.ffP) { - SigSpec D; - //if (st.muxP) - // D = st.muxP->getPort("\\B"); - //else - D = st.ffP->getPort("\\D"); - SigSpec Q = st.ffP->getPort("\\Q"); - P.replace(pm.sigmap(D), Q); - cell->setParam("\\PREG", State::S1); - if (st.ffP->type == "$dff") + if (st.ffPmux) { + cell->setPort("\\CEP", st.ffPmux->getPort("\\S")); + st.ffPmux->connections_.at("\\Y").replace(P, pm.module->addWire(NEW_ID, GetSize(P))); + } + else cell->setPort("\\CEP", State::S1); - //else if (st.ffP->type == "$dffe") - // cell->setPort("\\CEP", st.ffP->getPort("\\EN")); - else log_abort(); - + SigSpec D = st.ffP->getPort("\\D"); + SigSpec Q = st.ffP->getPort("\\Q"); + P.replace(/*pm.sigmap*/(D), Q); st.ffP->connections_.at("\\Q").replace(P, pm.module->addWire(NEW_ID, GetSize(P))); + + cell->setParam("\\PREG", State::S1); } log(" clock: %s (%s)", log_signal(st.clock), "posedge"); diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 2681cdbca..a2a6f2ef0 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -2,7 +2,7 @@ pattern xilinx_dsp state clock state sigA sigffAmux sigB sigffBmux sigC sigM sigP -state ffAmuxAB ffBmuxAB ffMmuxAB postAddAB postAddMuxAB +state ffAmuxAB ffBmuxAB ffMmuxAB ffPmuxAB postAddAB postAddMuxAB match dsp select dsp->type.in(\DSP48E1) @@ -120,7 +120,7 @@ match ffMmux filter port(ffMmux, AB) == sigM.extract(0, GetSize(port(ffMmux, \Y))) filter nusers(sigM.extract_end(GetSize(port(ffMmux, AB)))) <= 1 set ffMmuxAB AB - optional + semioptional endmatch code sigM @@ -199,6 +199,22 @@ code sigC sigP } endcode +match ffPmux + select ffPmux->type.in($mux) + select nusers(port(ffPmux, \Y)) == 2 + filter GetSize(port(ffPmux, \Y)) <= GetSize(sigP) + choice AB {\A, \B} + filter port(ffPmux, AB) == sigP.extract(0, GetSize(port(ffPmux, \Y))) + filter nusers(sigP.extract_end(GetSize(port(ffPmux, AB)))) <= 1 + set ffPmuxAB AB + semioptional +endmatch + +code sigP + if (ffPmux) + sigP = port(ffPmux, \Y); +endcode + match ffP if param(dsp, \PREG).as_int() == 0 select ffP->type.in($dff) @@ -207,6 +223,8 @@ match ffP filter GetSize(port(ffP, \D)) >= GetSize(sigP) slice offset GetSize(port(ffP, \D)) filter offset+GetSize(sigP) <= GetSize(port(ffP, \D)) && port(ffP, \D).extract(offset, GetSize(sigP)) == sigP + // Check ffPmux (when present) is a $dff enable mux + filter !ffPmux || port(ffP, \Q) == port(ffPmux, ffPmuxAB == \A ? \B : \A) optional endmatch -- cgit v1.2.3 From fe5a1324c953cee51774228723e73a2ecac9a45b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 5 Sep 2019 11:46:38 -0700 Subject: Do not make ff[MP]mux semioptional, use sigmap --- passes/pmgen/xilinx_dsp.cc | 7 +++++-- passes/pmgen/xilinx_dsp.pmg | 9 ++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index a497d0a48..6e82ffac3 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -121,7 +121,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) cell->setPort("\\CEM", State::S1); SigSpec D = st.ffM->getPort("\\D"); SigSpec Q = st.ffM->getPort("\\Q"); - P.replace(/*pm.sigmap*/(D), Q); + P.replace(pm.sigmap(D), Q); cell->setParam("\\MREG", State::S1); pm.autoremove(st.ffM); @@ -135,7 +135,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) cell->setPort("\\CEP", State::S1); SigSpec D = st.ffP->getPort("\\D"); SigSpec Q = st.ffP->getPort("\\Q"); - P.replace(/*pm.sigmap*/(D), Q); + P.replace(pm.sigmap(D), Q); st.ffP->connections_.at("\\Q").replace(P, pm.module->addWire(NEW_ID, GetSize(P))); cell->setParam("\\PREG", State::S1); @@ -149,6 +149,9 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) if (st.ffB) log(" ffB:%s", log_id(st.ffB)); + if (st.ffM) + log(" ffM:%s", log_id(st.ffM)); + if (st.ffP) log(" ffP:%s", log_id(st.ffP)); diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index a2a6f2ef0..d7632da6f 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -120,7 +120,7 @@ match ffMmux filter port(ffMmux, AB) == sigM.extract(0, GetSize(port(ffMmux, \Y))) filter nusers(sigM.extract_end(GetSize(port(ffMmux, AB)))) <= 1 set ffMmuxAB AB - semioptional + optional endmatch code sigM @@ -207,12 +207,12 @@ match ffPmux filter port(ffPmux, AB) == sigP.extract(0, GetSize(port(ffPmux, \Y))) filter nusers(sigP.extract_end(GetSize(port(ffPmux, AB)))) <= 1 set ffPmuxAB AB - semioptional + optional endmatch code sigP if (ffPmux) - sigP = port(ffPmux, \Y); + sigP.replace(port(ffPmux, ffPmuxAB), port(ffPmux, \Y)); endcode match ffP @@ -243,6 +243,9 @@ code ffP sigP clock sigP.replace(port(ffP, \D), port(ffP, \Q)); } + // Cannot have ffPmux enable mux without ffP + else if (ffPmux) + reject; endcode match postAddMux -- cgit v1.2.3 From 7bd55f379ca3bf8f79c290e9851d14b20c1f5c28 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 5 Sep 2019 11:55:14 -0700 Subject: Use filter instead of index; support wide enable muxes --- passes/pmgen/xilinx_dsp.pmg | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index d7632da6f..cee1906d6 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -66,9 +66,11 @@ endcode match ffAmux if ffA select ffAmux->type.in($mux) + filter GetSize(port(ffAmux, \Y)) >= GetSize(sigA) + slice offset GetSize(port(ffAmux, \Y)) + filter offset+GetSize(sigA) <= GetSize(port(ffAmux, \Y)) && port(ffAmux, \Y).extract(offset, GetSize(sigA)) == sigA choice AB {\A, \B} - index port(ffAmux, \Y) === sigA - index port(ffAmux, AB) === sigffAmux + filter offset+GetSize(sigffAmux) <= GetSize(port(ffAmux, \Y)) && port(ffAmux, AB).extract(offset, GetSize(sigffAmux)) == sigffAmux set ffAmuxAB AB semioptional endmatch @@ -105,9 +107,11 @@ endcode match ffBmux if ffB select ffBmux->type.in($mux) + filter GetSize(port(ffBmux, \Y)) >= GetSize(sigB) + slice offset GetSize(port(ffBmux, \Y)) + filter offset+GetSize(sigB) <= GetSize(port(ffBmux, \Y)) && port(ffBmux, \Y).extract(offset, GetSize(sigB)) == sigB choice AB {\A, \B} - index port(ffBmux, \Y) === sigB - index port(ffBmux, AB) === sigffBmux + filter offset+GetSize(sigffBmux) <= GetSize(port(ffBmux, \Y)) && port(ffBmux, AB).extract(offset, GetSize(sigffBmux)) == sigffBmux set ffBmuxAB AB semioptional endmatch -- cgit v1.2.3 From a32b14a55f888664981dc6b1184b00f34f5f4201 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 5 Sep 2019 12:38:47 -0700 Subject: Do not check signedness of post-adder (assume taken care of by DSP) --- passes/pmgen/xilinx_dsp.cc | 2 -- passes/pmgen/xilinx_dsp.pmg | 1 - 2 files changed, 3 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 6e82ffac3..9291c2dfb 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -52,8 +52,6 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) SigSpec P = st.sigP; if (st.postAdd) { - log_assert(st.postAdd->getParam("\\A_SIGNED").as_bool()); - log_assert(st.postAdd->getParam("\\B_SIGNED").as_bool()); log(" adder %s (%s)\n", log_id(st.postAdd), log_id(st.postAdd->type)); SigSpec &opmode = cell->connections_.at("\\OPMODE"); diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index cee1906d6..fa490146c 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -173,7 +173,6 @@ match postAdd if port(dsp, \OPMODE).extract(4,3).is_fully_zero() select postAdd->type.in($add) - select param(postAdd, \A_SIGNED).as_bool() && param(postAdd, \B_SIGNED).as_bool() choice AB {\A, \B} select nusers(port(postAdd, AB)) <= 3 filter ffMmux || nusers(port(postAdd, AB)) == 2 -- cgit v1.2.3 From 888ae1d05e322666821262218a87b3f5577b66d0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 5 Sep 2019 17:58:19 -0700 Subject: Fix broken ice40_dsp --- passes/pmgen/ice40_dsp.cc | 38 +++++------ passes/pmgen/ice40_dsp.pmg | 156 ++++++++++++++++++--------------------------- 2 files changed, 83 insertions(+), 111 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 31e11c742..8f5191be7 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -28,6 +28,7 @@ PRIVATE_NAMESPACE_BEGIN void create_ice40_dsp(ice40_dsp_pm &pm) { auto &st = pm.st_ice40_dsp; + Cell* ffO = st.ffO ? st.ffO : st.ffO_lo; #if 1 log("\n"); @@ -37,8 +38,7 @@ void create_ice40_dsp(ice40_dsp_pm &pm) log("ffFJKG: %s\n", log_id(st.ffFJKG, "--")); log("addAB: %s\n", log_id(st.addAB, "--")); log("muxAB: %s\n", log_id(st.muxAB, "--")); - log("ffO_lo: %s\n", log_id(st.ffO_lo, "--")); - log("ffO_hi: %s\n", log_id(st.ffO_hi, "--")); + log("ffO: %s\n", log_id(ffO, "--")); #endif log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(st.mul)); @@ -118,10 +118,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm) if (st.ffFJKG) log(" ffFJKG:%s", log_id(st.ffFJKG)); - if (st.ffO_lo) - log(" ffO_lo:%s", log_id(st.ffO_lo)); - if (st.ffO_hi) - log(" ffO_hi:%s", log_id(st.ffO_hi)); + if (ffO) + log(" ffO:%s", log_id(ffO)); log("\n"); } @@ -167,9 +165,9 @@ void create_ice40_dsp(ice40_dsp_pm &pm) bool accum = false; if (st.addAB) { if (st.addA) - accum = (st.ffO_lo && st.ffO_hi && st.addAB->getPort("\\B") == st.sigO); + accum = (ffO && st.addAB->getPort("\\B") == st.sigO); else if (st.addB) - accum = (st.ffO_lo && st.ffO_hi && st.addAB->getPort("\\A") == st.sigO); + accum = (ffO && st.addAB->getPort("\\A") == st.sigO); else log_abort(); if (accum) log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); @@ -207,12 +205,10 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam("\\PIPELINE_16x16_MULT_REG1", st.ffFJKG ? State::S1 : State::S0); cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0); - cell->setParam("\\TOPOUTPUT_SELECT", Const(st.ffO_hi ? 1 : (st.addAB ? 0 : 3), 2)); cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2)); cell->setParam("\\TOPADDSUB_UPPERINPUT", accum ? State::S0 : State::S1); cell->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2)); - cell->setParam("\\BOTOUTPUT_SELECT", Const(st.ffO_lo ? 1 : (st.addAB ? 0 : 3), 2)); cell->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2)); cell->setParam("\\BOTADDSUB_UPPERINPUT", accum ? State::S0 : State::S1); cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2)); @@ -221,20 +217,26 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam("\\A_SIGNED", st.mul->getParam("\\A_SIGNED").as_bool()); cell->setParam("\\B_SIGNED", st.mul->getParam("\\B_SIGNED").as_bool()); + if (ffO) { + if (st.ffO) + cell->setParam("\\TOPOUTPUT_SELECT", Const(1, 2)); + else + cell->setParam("\\TOPOUTPUT_SELECT", Const(st.addAB ? 0 : 3, 2)); + + ffO->connections_.at("\\Q").replace(O, pm.module->addWire(NEW_ID, GetSize(O))); + cell->setParam("\\BOTOUTPUT_SELECT", Const(1, 2)); + } + else { + cell->setParam("\\TOPOUTPUT_SELECT", Const(st.addAB ? 0 : 3, 2)); + cell->setParam("\\BOTOUTPUT_SELECT", Const(st.addAB ? 0 : 3, 2)); + } + if (cell != st.mul) pm.autoremove(st.mul); else pm.blacklist(st.mul); pm.autoremove(st.ffFJKG); pm.autoremove(st.addAB); - if (st.ffO_lo) { - SigSpec O = st.sigO.extract(0,std::min(16,st.ffO_lo->getParam("\\WIDTH").as_int())); - st.ffO_lo->connections_.at("\\Q").replace(O, pm.module->addWire(NEW_ID, GetSize(O))); - } - if (st.ffO_hi) { - SigSpec O = st.sigO.extract_end(16); - st.ffO_hi->connections_.at("\\Q").replace(O, pm.module->addWire(NEW_ID, GetSize(O))); - } } struct Ice40DspPass : public Pass { diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 8221cdb69..4baea8aef 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -1,7 +1,7 @@ pattern ice40_dsp state clock -state clock_pol +state clock_pol cd_signed state > sigAset sigBset state sigA sigB sigCD sigH sigO sigOused state addAB muxAB @@ -21,13 +21,22 @@ code sigAset sigBset endcode code sigH + SigSpec O; if (mul->type == $mul) - sigH = mul->getPort(\Y); + O = mul->getPort(\Y); else if (mul->type == \SB_MAC16) - sigH = mul->getPort(\O); + O = mul->getPort(\O); else log_abort(); - if (GetSize(sigH) <= 10) + if (GetSize(O) <= 10) reject; + // Only care about those bits that are used + int i; + for (i = 0; i < GetSize(O); i++) { + if (nusers(O[i]) <= 1) + break; + sigH.append(O[i]); + } + log_assert(nusers(O.extract_end(i)) <= 1); endcode match ffA @@ -136,17 +145,16 @@ match addB optional endmatch -code addAB sigCD sigO - bool CD_SIGNED = false; +code addAB sigCD sigO cd_signed if (addA) { addAB = addA; sigCD = port(addAB, \B); - CD_SIGNED = param(addAB, \B_SIGNED).as_bool(); + cd_signed = param(addAB, \B_SIGNED).as_bool(); } - if (addB) { + else if (addB) { addAB = addB; sigCD = port(addAB, \A); - CD_SIGNED = param(addAB, \A_SIGNED).as_bool(); + cd_signed = param(addAB, \A_SIGNED).as_bool(); } if (addAB) { if (mul->type == \SB_MAC16) { @@ -167,7 +175,6 @@ code addAB sigCD sigO reject; sigO = port(addAB, \Y); - sigCD.extend_u0(32, CD_SIGNED); } endcode @@ -186,105 +193,63 @@ match muxB optional endmatch -code muxAB +code muxAB sigO if (muxA) muxAB = muxA; else if (muxB) muxAB = muxB; + if (muxAB) + sigO = port(muxAB, \Y); endcode -// Extract the bits of P that actually have a consumer -// (as opposed to being a dummy) -code sigOused - for (int i = 0; i < GetSize(sigO); i++) - if (!sigO[i].wire || nusers(sigO[i]) == 1) - sigOused.append(State::Sx); - else - sigOused.append(sigO[i]); -endcode - -match ffO_lo - if nusers(sigOused.extract(0,std::min(16,GetSize(sigOused)))) == 2 - select ffO_lo->type.in($dff) +match ffO + // Ensure that register is not already used + if mul->type != \SB_MAC16 || (mul->parameters.at(\TOPOUTPUT_SELECT, 0).as_int() != 1 && mul->parameters.at(\BOTOUTPUT_SELECT, 0).as_int() != 1) + // Ensure that OLOADTOP/OLOADBOT is unused or zero + if mul->type != \SB_MAC16 || (mul->connections_.at(\OLOADTOP, State::S0).is_fully_zero() && mul->connections_.at(\OLOADBOT, State::S0).is_fully_zero()) + if nusers(sigO) == 2 + select ffO->type.in($dff) + filter GetSize(port(ffO, \D)) >= GetSize(sigO) + slice offset GetSize(port(ffO, \D)) + filter offset+GetSize(sigO) <= GetSize(port(ffO, \D)) && port(ffO, \D).extract(offset, GetSize(sigO)) == sigO optional endmatch -code - if (ffO_lo) { - SigSpec O = sigOused.extract(0,std::min(16,param(ffO_lo, \WIDTH).as_int())); - O.remove_const(); - auto ffO_loSet = port(ffO_lo, \D).to_sigbit_set(); - auto Oset = O.to_sigbit_set(); - if (!std::includes(ffO_loSet.begin(), ffO_loSet.end(), Oset.begin(), Oset.end())) - reject; - } -endcode - -match ffO_hi - if GetSize(sigOused) > 16 - if nusers(sigOused.extract_end(16)) == 2 - select ffO_hi->type.in($dff) +match ffO_lo + if !ffO && GetSize(sigO) > 16 + // Ensure that register is not already used + if mul->type != \SB_MAC16 || (mul->parameters.at(\TOPOUTPUT_SELECT, 0).as_int() != 1 && mul->parameters.at(\BOTOUTPUT_SELECT, 0).as_int() != 1) + // Ensure that OLOADTOP/OLOADBOT is unused or zero + if mul->type != \SB_MAC16 || (mul->connections_.at(\OLOADTOP, State::S0).is_fully_zero() && mul->connections_.at(\OLOADBOT, State::S0).is_fully_zero()) + if nusers(sigO.extract(0, 16)) == 2 + select ffO_lo->type.in($dff) + filter GetSize(port(ffO_lo, \D)) >= 16 + slice offset GetSize(port(ffO_lo, \D)) + filter offset+GetSize(sigO) <= GetSize(port(ffO_lo, \D)) && port(ffO_lo, \D).extract(offset, 16) == sigO.extract(0, 16) optional endmatch -code - if (ffO_hi) { - SigSpec O = sigOused.extract_end(16); - O.remove_const(); - auto ffO_hiSet = port(ffO_hi, \D).to_sigbit_set(); - auto Oset = O.to_sigbit_set(); - if (!std::includes(ffO_hiSet.begin(), ffO_hiSet.end(), Oset.begin(), Oset.end())) - reject; - } -endcode - -code clock clock_pol sigO sigCD - if (ffO_lo || ffO_hi) { - if (mul->type == \SB_MAC16) { - // Ensure that register is not already used - if (param(mul, \TOPOUTPUT_SELECT).as_int() == 1 || - param(mul, \BOTOUTPUT_SELECT).as_int() == 1) - reject; - - // Ensure that OLOADTOP/OLOADBOT is unused or zero - if ((mul->hasPort(\OLOADTOP) && !port(mul, \OLOADTOP).is_fully_zero()) - || (mul->hasPort(\OLOADBOT) && !port(mul, \OLOADBOT).is_fully_zero())) - reject; - } - - if (ffO_lo) { - for (auto b : port(ffO_lo, \Q)) - if (b.wire->get_bool_attribute(\keep)) - reject; - - SigBit c = port(ffO_lo, \CLK).as_bit(); - bool cp = param(ffO_lo, \CLK_POLARITY).as_bool(); - - if (clock != SigBit() && (c != clock || cp != clock_pol)) +code clock clock_pol sigO sigCD cd_signed + Cell* ff = nullptr; + if (ffO) + ff = ffO; + else if (ffO_lo) + ff = ffO_lo; + if (ff) { + for (auto b : port(ff, \Q)) + if (b.wire->get_bool_attribute(\keep)) reject; - clock = c; - clock_pol = cp; - - sigO.replace(port(ffO_lo, \D), port(ffO_lo, \Q)); - } - - if (ffO_hi) { - for (auto b : port(ffO_hi, \Q)) - if (b.wire->get_bool_attribute(\keep)) - reject; - - SigBit c = port(ffO_hi, \CLK).as_bit(); - bool cp = param(ffO_hi, \CLK_POLARITY).as_bool(); + SigBit c = port(ff, \CLK).as_bit(); + bool cp = param(ff, \CLK_POLARITY).as_bool(); - if (clock != SigBit() && (c != clock || cp != clock_pol)) - reject; + if (clock != SigBit() && (c != clock || cp != clock_pol)) + reject; - clock = c; - clock_pol = cp; + clock = c; + clock_pol = cp; - sigO.replace(port(ffO_hi, \D), port(ffO_hi, \Q)); - } + sigO.replace(port(ff, \D), port(ff, \Q)); // Loading value into output register is not // supported unless using accumulator @@ -296,8 +261,13 @@ code clock clock_pol sigO sigCD else if (muxB) sigCD = port(muxAB, \A); else log_abort(); - sigCD.extend_u0(32, addAB && param(addAB, \A_SIGNED).as_bool() && param(addAB, \B_SIGNED).as_bool()); + + cd_signed = addAB && param(addAB, \A_SIGNED).as_bool() && param(addAB, \B_SIGNED).as_bool(); } } + sigCD.extend_u0(32, cd_signed); +endcode + +code accept; endcode -- cgit v1.2.3 From 5a2fc6fcb5141573cbfcebdec4354fc11056a8f4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 5 Sep 2019 18:06:59 -0700 Subject: Refactor ice40_dsp --- passes/pmgen/ice40_dsp.cc | 2 ++ passes/pmgen/ice40_dsp.pmg | 54 +++++++++++++++++++++++----------------------- 2 files changed, 29 insertions(+), 27 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 8f5191be7..f62f627bb 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -74,9 +74,11 @@ void create_ice40_dsp(ice40_dsp_pm &pm) // SB_MAC16 Input Interface SigSpec A = st.sigA; + A.extend_u0(16, st.mul->getParam("\\A_SIGNED").as_bool()); log_assert(GetSize(A) == 16); SigSpec B = st.sigB; + B.extend_u0(16, st.mul->getParam("\\B_SIGNED").as_bool()); log_assert(GetSize(B) == 16); SigSpec CD = st.sigCD; diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 4baea8aef..1219e0d24 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -2,8 +2,7 @@ pattern ice40_dsp state clock state clock_pol cd_signed -state > sigAset sigBset -state sigA sigB sigCD sigH sigO sigOused +state sigA sigB sigCD sigH sigO state addAB muxAB match mul @@ -11,16 +10,7 @@ match mul select GetSize(mul->getPort(\A)) + GetSize(mul->getPort(\B)) > 10 endmatch -code sigAset sigBset - SigSpec A = port(mul, \A); - A.remove_const(); - sigAset = A.to_sigbit_set(); - SigSpec B = port(mul, \B); - B.remove_const(); - sigBset = B.to_sigbit_set(); -endcode - -code sigH +code sigA sigB sigH SigSpec O; if (mul->type == $mul) O = mul->getPort(\Y); @@ -29,8 +19,26 @@ code sigH else log_abort(); if (GetSize(O) <= 10) reject; - // Only care about those bits that are used + + sigA = port(mul, \A); int i; + for (i = GetSize(sigA)-1; i > 0; i--) + if (sigA[i] != sigA[i-1]) + break; + // Do not remove non-const sign bit + if (sigA[i].wire) + ++i; + sigA.remove(i, GetSize(sigA)-i); + sigB = port(mul, \B); + for (i = GetSize(sigB)-1; i > 0; i--) + if (sigB[i] != sigB[i-1]) + break; + // Do not remove non-const sign bit + if (sigB[i].wire) + ++i; + sigB.remove(i, GetSize(sigB)-i); + + // Only care about those bits that are used for (i = 0; i < GetSize(O); i++) { if (nusers(O[i]) <= 1) break; @@ -41,19 +49,15 @@ endcode match ffA if mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool() - if !sigAset.empty() select ffA->type.in($dff) + filter GetSize(port(ffA, \Q)) >= GetSize(sigA) + slice offset GetSize(port(ffA, \Q)) + filter offset+GetSize(sigA) <= GetSize(port(ffA, \Q)) && port(ffA, \Q).extract(offset, GetSize(sigA)) == sigA optional endmatch code sigA clock clock_pol - sigA = port(mul, \A); - if (ffA) { - auto ffAset = port(ffA, \Q).to_sigbit_set(); - if (!std::includes(ffAset.begin(), ffAset.end(), sigAset.begin(), sigAset.end())) - reject; - for (auto b : port(ffA, \Q)) if (b.wire->get_bool_attribute(\keep)) reject; @@ -67,19 +71,15 @@ endcode match ffB if mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool() - if !sigBset.empty() select ffB->type.in($dff) + filter GetSize(port(ffB, \Q)) >= GetSize(sigB) + slice offset GetSize(port(ffB, \Q)) + filter offset+GetSize(sigB) <= GetSize(port(ffB, \Q)) && port(ffB, \Q).extract(offset, GetSize(sigB)) == sigB optional endmatch code sigB clock clock_pol - sigB = port(mul, \B); - if (ffB) { - auto ffBset = port(ffB, \Q).to_sigbit_set(); - if (!std::includes(ffBset.begin(), ffBset.end(), sigBset.begin(), sigBset.end())) - reject; - for (auto b : port(ffB, \Q)) if (b.wire->get_bool_attribute(\keep)) reject; -- cgit v1.2.3 From 53ca536d674ade382da16adddfb02db7e970acef Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 5 Sep 2019 21:28:28 -0700 Subject: ffAmuxAB -> ffAenpol --- passes/pmgen/xilinx_dsp.cc | 5 +++-- passes/pmgen/xilinx_dsp.pmg | 10 ++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 9291c2dfb..16a098fd0 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -83,9 +83,10 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) A.replace(Q, D); if (st.ffAmux) { SigSpec Y = st.ffAmux->getPort("\\Y"); - SigSpec AB = st.ffAmux->getPort(st.ffAmuxAB == "\\A" ? "\\B" : "\\A"); + SigSpec AB = st.ffAmux->getPort(st.ffAenpol ? "\\A" : "\\B"); A.replace(Y, AB); - cell->setPort("\\CEA2", st.ffAmux->getPort("\\S")); + SigSpec S = st.ffAmux->getPort("\\S"); + cell->setPort("\\CEA2", st.ffAenpol ? S : pm.module->Not(NEW_ID, S)); } else cell->setPort("\\CEA2", State::S1); diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index fa490146c..579935869 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -2,7 +2,8 @@ pattern xilinx_dsp state clock state sigA sigffAmux sigB sigffBmux sigC sigM sigP -state ffAmuxAB ffBmuxAB ffMmuxAB ffPmuxAB postAddAB postAddMuxAB +state ffBmuxAB ffMmuxAB ffPmuxAB postAddAB postAddMuxAB +state ffAenpol match dsp select dsp->type.in(\DSP48E1) @@ -69,9 +70,10 @@ match ffAmux filter GetSize(port(ffAmux, \Y)) >= GetSize(sigA) slice offset GetSize(port(ffAmux, \Y)) filter offset+GetSize(sigA) <= GetSize(port(ffAmux, \Y)) && port(ffAmux, \Y).extract(offset, GetSize(sigA)) == sigA - choice AB {\A, \B} - filter offset+GetSize(sigffAmux) <= GetSize(port(ffAmux, \Y)) && port(ffAmux, AB).extract(offset, GetSize(sigffAmux)) == sigffAmux - set ffAmuxAB AB + choice BA {\B, \A} + filter offset+GetSize(sigffAmux) <= GetSize(port(ffAmux, \Y)) && port(ffAmux, BA).extract(offset, GetSize(sigffAmux)) == sigffAmux + define pol (BA == \B) + set ffAenpol pol semioptional endmatch -- cgit v1.2.3 From 174edbcb96f780592cde1952db6ee7e58e8e2f56 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 5 Sep 2019 21:38:35 -0700 Subject: Sensitive to CEB CEM CEP polarity --- passes/pmgen/xilinx_dsp.cc | 13 ++++++++----- passes/pmgen/xilinx_dsp.pmg | 35 +++++++++++++++++++---------------- 2 files changed, 27 insertions(+), 21 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 16a098fd0..38b1a12be 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -84,8 +84,8 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) if (st.ffAmux) { SigSpec Y = st.ffAmux->getPort("\\Y"); SigSpec AB = st.ffAmux->getPort(st.ffAenpol ? "\\A" : "\\B"); - A.replace(Y, AB); SigSpec S = st.ffAmux->getPort("\\S"); + A.replace(Y, AB); cell->setPort("\\CEA2", st.ffAenpol ? S : pm.module->Not(NEW_ID, S)); } else @@ -101,9 +101,10 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) B.replace(Q, D); if (st.ffBmux) { SigSpec Y = st.ffBmux->getPort("\\Y"); - SigSpec AB = st.ffBmux->getPort(st.ffBmuxAB == "\\A" ? "\\B" : "\\A"); + SigSpec AB = st.ffBmux->getPort(st.ffBenpol ? "\\A" : "\\B"); + SigSpec S = st.ffBmux->getPort("\\S"); B.replace(Y, AB); - cell->setPort("\\CEB2", st.ffBmux->getPort("\\S")); + cell->setPort("\\CEB2", st.ffBenpol ? S : pm.module->Not(NEW_ID, S)); } else cell->setPort("\\CEB2", State::S1); @@ -113,7 +114,8 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) } if (st.ffM) { if (st.ffMmux) { - cell->setPort("\\CEM", st.ffMmux->getPort("\\S")); + SigSpec S = st.ffMmux->getPort("\\S"); + cell->setPort("\\CEM", st.ffMenpol ? S : pm.module->Not(NEW_ID, S)); pm.autoremove(st.ffMmux); } else @@ -127,7 +129,8 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) } if (st.ffP) { if (st.ffPmux) { - cell->setPort("\\CEP", st.ffPmux->getPort("\\S")); + SigSpec S = st.ffPmux->getPort("\\S"); + cell->setPort("\\CEP", st.ffPenpol ? S : pm.module->Not(NEW_ID, S)); st.ffPmux->connections_.at("\\Y").replace(P, pm.module->addWire(NEW_ID, GetSize(P))); } else diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 579935869..a86501d29 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -2,8 +2,8 @@ pattern xilinx_dsp state clock state sigA sigffAmux sigB sigffBmux sigC sigM sigP -state ffBmuxAB ffMmuxAB ffPmuxAB postAddAB postAddMuxAB -state ffAenpol +state postAddAB postAddMuxAB +state ffAenpol ffBenpol ffMenpol ffPenpol match dsp select dsp->type.in(\DSP48E1) @@ -112,9 +112,10 @@ match ffBmux filter GetSize(port(ffBmux, \Y)) >= GetSize(sigB) slice offset GetSize(port(ffBmux, \Y)) filter offset+GetSize(sigB) <= GetSize(port(ffBmux, \Y)) && port(ffBmux, \Y).extract(offset, GetSize(sigB)) == sigB - choice AB {\A, \B} - filter offset+GetSize(sigffBmux) <= GetSize(port(ffBmux, \Y)) && port(ffBmux, AB).extract(offset, GetSize(sigffBmux)) == sigffBmux - set ffBmuxAB AB + choice BA {\B, \A} + filter offset+GetSize(sigffBmux) <= GetSize(port(ffBmux, \Y)) && port(ffBmux, BA).extract(offset, GetSize(sigffBmux)) == sigffBmux + define pol (BA == \B) + set ffBenpol pol semioptional endmatch @@ -122,10 +123,11 @@ match ffMmux select ffMmux->type.in($mux) select nusers(port(ffMmux, \Y)) == 2 filter GetSize(port(ffMmux, \Y)) <= GetSize(sigM) - choice AB {\A, \B} - filter port(ffMmux, AB) == sigM.extract(0, GetSize(port(ffMmux, \Y))) - filter nusers(sigM.extract_end(GetSize(port(ffMmux, AB)))) <= 1 - set ffMmuxAB AB + choice BA {\B, \A} + filter port(ffMmux, BA) == sigM.extract(0, GetSize(port(ffMmux, \Y))) + filter nusers(sigM.extract_end(GetSize(port(ffMmux, BA)))) <= 1 + define pol (BA == \B) + set ffMenpol pol optional endmatch @@ -144,7 +146,7 @@ match ffM filter port(ffM, \D) == sigM.extract(0, GetSize(port(ffM, \D))) filter nusers(sigM.extract_end(GetSize(port(ffM, \D)))) <= 1 // Check ffMmux (when present) is a $dff enable mux - filter !ffMmux || port(ffM, \Q) == port(ffMmux, ffMmuxAB == \A ? \B : \A) + filter !ffMmux || port(ffM, \Q) == port(ffMmux, ffMenpol ? \A : \B) optional endmatch @@ -208,16 +210,17 @@ match ffPmux select ffPmux->type.in($mux) select nusers(port(ffPmux, \Y)) == 2 filter GetSize(port(ffPmux, \Y)) <= GetSize(sigP) - choice AB {\A, \B} - filter port(ffPmux, AB) == sigP.extract(0, GetSize(port(ffPmux, \Y))) - filter nusers(sigP.extract_end(GetSize(port(ffPmux, AB)))) <= 1 - set ffPmuxAB AB + choice BA {\B, \A} + filter port(ffPmux, BA) == sigP.extract(0, GetSize(port(ffPmux, \Y))) + filter nusers(sigP.extract_end(GetSize(port(ffPmux, BA)))) <= 1 + define pol (BA == \B) + set ffPenpol pol optional endmatch code sigP if (ffPmux) - sigP.replace(port(ffPmux, ffPmuxAB), port(ffPmux, \Y)); + sigP.replace(port(ffPmux, ffPenpol ? \A : \B), port(ffPmux, \Y)); endcode match ffP @@ -229,7 +232,7 @@ match ffP slice offset GetSize(port(ffP, \D)) filter offset+GetSize(sigP) <= GetSize(port(ffP, \D)) && port(ffP, \D).extract(offset, GetSize(sigP)) == sigP // Check ffPmux (when present) is a $dff enable mux - filter !ffPmux || port(ffP, \Q) == port(ffPmux, ffPmuxAB == \A ? \B : \A) + filter !ffPmux || port(ffP, \Q) == port(ffPmux, ffPenpol ? \A : \B) optional endmatch -- cgit v1.2.3 From dc10559f31410e2395e1321d6ca6126024c7cea3 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 5 Sep 2019 21:39:52 -0700 Subject: Cleanup --- passes/pmgen/ice40_dsp.cc | 17 ++++++++--------- passes/pmgen/ice40_dsp.pmg | 34 +++++++++++++++++----------------- 2 files changed, 25 insertions(+), 26 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index f62f627bb..7858b8972 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -28,7 +28,6 @@ PRIVATE_NAMESPACE_BEGIN void create_ice40_dsp(ice40_dsp_pm &pm) { auto &st = pm.st_ice40_dsp; - Cell* ffO = st.ffO ? st.ffO : st.ffO_lo; #if 1 log("\n"); @@ -38,7 +37,7 @@ void create_ice40_dsp(ice40_dsp_pm &pm) log("ffFJKG: %s\n", log_id(st.ffFJKG, "--")); log("addAB: %s\n", log_id(st.addAB, "--")); log("muxAB: %s\n", log_id(st.muxAB, "--")); - log("ffO: %s\n", log_id(ffO, "--")); + log("ffO: %s\n", log_id(st.ffO, "--")); #endif log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(st.mul)); @@ -120,8 +119,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm) if (st.ffFJKG) log(" ffFJKG:%s", log_id(st.ffFJKG)); - if (ffO) - log(" ffO:%s", log_id(ffO)); + if (st.ffO) + log(" ffO:%s", log_id(st.ffO)); log("\n"); } @@ -167,9 +166,9 @@ void create_ice40_dsp(ice40_dsp_pm &pm) bool accum = false; if (st.addAB) { if (st.addA) - accum = (ffO && st.addAB->getPort("\\B") == st.sigO); + accum = (st.ffO && st.addAB->getPort("\\B") == st.sigO); else if (st.addB) - accum = (ffO && st.addAB->getPort("\\A") == st.sigO); + accum = (st.ffO && st.addAB->getPort("\\A") == st.sigO); else log_abort(); if (accum) log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); @@ -219,13 +218,13 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam("\\A_SIGNED", st.mul->getParam("\\A_SIGNED").as_bool()); cell->setParam("\\B_SIGNED", st.mul->getParam("\\B_SIGNED").as_bool()); - if (ffO) { - if (st.ffO) + if (st.ffO) { + if (st.ffO_hilo) cell->setParam("\\TOPOUTPUT_SELECT", Const(1, 2)); else cell->setParam("\\TOPOUTPUT_SELECT", Const(st.addAB ? 0 : 3, 2)); - ffO->connections_.at("\\Q").replace(O, pm.module->addWire(NEW_ID, GetSize(O))); + st.ffO->connections_.at("\\Q").replace(O, pm.module->addWire(NEW_ID, GetSize(O))); cell->setParam("\\BOTOUTPUT_SELECT", Const(1, 2)); } else { diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 1219e0d24..95e8da379 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -3,7 +3,7 @@ pattern ice40_dsp state clock state clock_pol cd_signed state sigA sigB sigCD sigH sigO -state addAB muxAB +state addAB muxAB ffO match mul select mul->type.in($mul, \SB_MAC16) @@ -202,21 +202,21 @@ code muxAB sigO sigO = port(muxAB, \Y); endcode -match ffO +match ffO_hilo // Ensure that register is not already used if mul->type != \SB_MAC16 || (mul->parameters.at(\TOPOUTPUT_SELECT, 0).as_int() != 1 && mul->parameters.at(\BOTOUTPUT_SELECT, 0).as_int() != 1) // Ensure that OLOADTOP/OLOADBOT is unused or zero if mul->type != \SB_MAC16 || (mul->connections_.at(\OLOADTOP, State::S0).is_fully_zero() && mul->connections_.at(\OLOADBOT, State::S0).is_fully_zero()) if nusers(sigO) == 2 - select ffO->type.in($dff) - filter GetSize(port(ffO, \D)) >= GetSize(sigO) - slice offset GetSize(port(ffO, \D)) - filter offset+GetSize(sigO) <= GetSize(port(ffO, \D)) && port(ffO, \D).extract(offset, GetSize(sigO)) == sigO + select ffO_hilo->type.in($dff) + filter GetSize(port(ffO_hilo, \D)) >= GetSize(sigO) + slice offset GetSize(port(ffO_hilo, \D)) + filter offset+GetSize(sigO) <= GetSize(port(ffO_hilo, \D)) && port(ffO_hilo, \D).extract(offset, GetSize(sigO)) == sigO optional endmatch match ffO_lo - if !ffO && GetSize(sigO) > 16 + if !ffO_hilo && GetSize(sigO) > 16 // Ensure that register is not already used if mul->type != \SB_MAC16 || (mul->parameters.at(\TOPOUTPUT_SELECT, 0).as_int() != 1 && mul->parameters.at(\BOTOUTPUT_SELECT, 0).as_int() != 1) // Ensure that OLOADTOP/OLOADBOT is unused or zero @@ -229,19 +229,19 @@ match ffO_lo optional endmatch -code clock clock_pol sigO sigCD cd_signed - Cell* ff = nullptr; - if (ffO) - ff = ffO; +code ffO clock clock_pol sigO sigCD cd_signed + ffO = nullptr; + if (ffO_hilo) + ffO = ffO_hilo; else if (ffO_lo) - ff = ffO_lo; - if (ff) { - for (auto b : port(ff, \Q)) + ffO = ffO_lo; + if (ffO) { + for (auto b : port(ffO, \Q)) if (b.wire->get_bool_attribute(\keep)) reject; - SigBit c = port(ff, \CLK).as_bit(); - bool cp = param(ff, \CLK_POLARITY).as_bool(); + SigBit c = port(ffO, \CLK).as_bit(); + bool cp = param(ffO, \CLK_POLARITY).as_bool(); if (clock != SigBit() && (c != clock || cp != clock_pol)) reject; @@ -249,7 +249,7 @@ code clock clock_pol sigO sigCD cd_signed clock = c; clock_pol = cp; - sigO.replace(port(ff, \D), port(ff, \Q)); + sigO.replace(port(ffO, \D), port(ffO, \Q)); // Loading value into output register is not // supported unless using accumulator -- cgit v1.2.3 From 4fe24b20f9c42e81bf0539c4b3bde9c4a471c5ea Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 09:47:32 -0700 Subject: More nusers() checks for A and B enable muxes --- passes/pmgen/xilinx_dsp.pmg | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index a86501d29..15343e21e 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,7 +1,7 @@ pattern xilinx_dsp state clock -state sigA sigffAmux sigB sigffBmux sigC sigM sigP +state sigA sigffAmuxY sigB sigffBmuxY sigC sigM sigP state postAddAB postAddMuxAB state ffAenpol ffBenpol ffMenpol ffPenpol @@ -9,7 +9,7 @@ match dsp select dsp->type.in(\DSP48E1) endmatch -code sigA sigffAmux sigB sigffBmux sigM +code sigA sigffAmuxY sigB sigffBmuxY sigM sigA = port(dsp, \A); int i; for (i = GetSize(sigA)-1; i > 0; i--) @@ -38,6 +38,9 @@ code sigA sigffAmux sigB sigffBmux sigM log_assert(nusers(P.extract_end(i)) <= 1); //if (GetSize(sigM) <= 10) // reject; + + sigffAmuxY = SigSpec(); + sigffBmuxY = SigSpec(); endcode match ffA @@ -51,7 +54,7 @@ match ffA optional endmatch -code sigA sigffAmux clock +code sigA sigffAmuxY clock if (ffA) { for (auto b : port(ffA, \Q)) if (b.wire->get_bool_attribute(\keep)) @@ -59,19 +62,25 @@ code sigA sigffAmux clock clock = port(ffA, \CLK).as_bit(); - sigffAmux = sigA; - sigA.replace(port(ffA, \Q), port(ffA, \D)); + SigSpec A = sigA; + A.replace(port(ffA, \Q), port(ffA, \D)); + // Only search for ffAmux if ffA.Q has at + // least 3 users (ffA, dsp, ffAmux) and + // its ffA.D only has two (ffA, ffAmux) + if (nusers(sigA) >= 3 && nusers(A) == 2) + sigffAmuxY = sigA; + sigA = std::move(A); } endcode match ffAmux - if ffA + if !sigffAmuxY.empty() select ffAmux->type.in($mux) filter GetSize(port(ffAmux, \Y)) >= GetSize(sigA) slice offset GetSize(port(ffAmux, \Y)) filter offset+GetSize(sigA) <= GetSize(port(ffAmux, \Y)) && port(ffAmux, \Y).extract(offset, GetSize(sigA)) == sigA choice BA {\B, \A} - filter offset+GetSize(sigffAmux) <= GetSize(port(ffAmux, \Y)) && port(ffAmux, BA).extract(offset, GetSize(sigffAmux)) == sigffAmux + filter offset+GetSize(sigffAmuxY) <= GetSize(port(ffAmux, \Y)) && port(ffAmux, BA).extract(offset, GetSize(sigffAmuxY)) == sigffAmuxY define pol (BA == \B) set ffAenpol pol semioptional @@ -88,32 +97,36 @@ match ffB optional endmatch -code sigB sigffBmux clock +code sigB sigffBmuxY clock if (ffB) { for (auto b : port(ffB, \Q)) if (b.wire->get_bool_attribute(\keep)) reject; SigBit c = port(ffB, \CLK).as_bit(); - if (clock != SigBit() && c != clock) reject; - clock = c; - sigffBmux = sigB; - sigB.replace(port(ffB, \Q), port(ffB, \D)); + SigSpec B = sigB; + B.replace(port(ffB, \Q), port(ffB, \D)); + // Only search for ffBmux if ffB.Q has at + // least 3 users (ffB, dsp, ffBmux) and + // its ffB.D only has two (ffB, ffBmux) + if (nusers(sigB) >= 3 && nusers(B) == 2) + sigffBmuxY = sigB; + sigB = std::move(B); } endcode match ffBmux - if ffB + if !sigffBmuxY.empty() select ffBmux->type.in($mux) filter GetSize(port(ffBmux, \Y)) >= GetSize(sigB) slice offset GetSize(port(ffBmux, \Y)) filter offset+GetSize(sigB) <= GetSize(port(ffBmux, \Y)) && port(ffBmux, \Y).extract(offset, GetSize(sigB)) == sigB choice BA {\B, \A} - filter offset+GetSize(sigffBmux) <= GetSize(port(ffBmux, \Y)) && port(ffBmux, BA).extract(offset, GetSize(sigffBmux)) == sigffBmux + filter offset+GetSize(sigffBmuxY) <= GetSize(port(ffBmux, \Y)) && port(ffBmux, BA).extract(offset, GetSize(sigffBmuxY)) == sigffBmuxY define pol (BA == \B) set ffBenpol pol semioptional -- cgit v1.2.3 From 91f68c4de2c1c9823e5c6a6257ded09144dfcbd6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 09:59:35 -0700 Subject: Check nusers for M and P enable muxes --- passes/pmgen/xilinx_dsp.pmg | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 15343e21e..8f83a2a50 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -134,10 +134,17 @@ endmatch match ffMmux select ffMmux->type.in($mux) + choice BA {\B, \A} + // new-value net must have exactly two users: dsp and ffM + select nusers(port(ffMmux, BA)) == 2 + define AB (BA == \B ? \A : \B) + // keep-last-value net must have at least three users: ffMmux, ffM, downstream sink(s) + select nusers(port(ffMmux, AB)) >= 3 + // ffMmux output must have two users: ffMmux and ffM.D select nusers(port(ffMmux, \Y)) == 2 filter GetSize(port(ffMmux, \Y)) <= GetSize(sigM) - choice BA {\B, \A} filter port(ffMmux, BA) == sigM.extract(0, GetSize(port(ffMmux, \Y))) + // Remaining bits on sigM must not have any other users filter nusers(sigM.extract_end(GetSize(port(ffMmux, BA)))) <= 1 define pol (BA == \B) set ffMenpol pol @@ -157,6 +164,7 @@ match ffM select nusers(port(ffM, \D)) == 2 filter GetSize(port(ffM, \D)) <= GetSize(sigM) filter port(ffM, \D) == sigM.extract(0, GetSize(port(ffM, \D))) + // Remaining bits on sigM must not have any other users filter nusers(sigM.extract_end(GetSize(port(ffM, \D)))) <= 1 // Check ffMmux (when present) is a $dff enable mux filter !ffMmux || port(ffM, \Q) == port(ffMmux, ffMenpol ? \A : \B) @@ -221,10 +229,17 @@ endcode match ffPmux select ffPmux->type.in($mux) + choice BA {\B, \A} + // new-value net must have exactly two users: dsp and ffP + select nusers(port(ffPmux, BA)) == 2 + define AB (BA == \B ? \A : \B) + // keep-last-value net must have at least three users: ffPmux, ffP, downstream sink(s) + select nusers(port(ffPmux, AB)) >= 3 + // ffPmux output must have two users: ffPmux and ffP.D select nusers(port(ffPmux, \Y)) == 2 filter GetSize(port(ffPmux, \Y)) <= GetSize(sigP) - choice BA {\B, \A} filter port(ffPmux, BA) == sigP.extract(0, GetSize(port(ffPmux, \Y))) + // Remaining bits on sigP must not have any other users filter nusers(sigP.extract_end(GetSize(port(ffPmux, BA)))) <= 1 define pol (BA == \B) set ffPenpol pol -- cgit v1.2.3 From cdc1e1f5c226d3597896555749ecfa3568a66c50 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 10:35:06 -0700 Subject: Check adder is <= 48 bits before packing --- passes/pmgen/xilinx_dsp.pmg | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 8f83a2a50..bb3bf90bd 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -83,7 +83,7 @@ match ffAmux filter offset+GetSize(sigffAmuxY) <= GetSize(port(ffAmux, \Y)) && port(ffAmux, BA).extract(offset, GetSize(sigffAmuxY)) == sigffAmuxY define pol (BA == \B) set ffAenpol pol - semioptional + optional endmatch match ffB @@ -129,7 +129,7 @@ match ffBmux filter offset+GetSize(sigffBmuxY) <= GetSize(port(ffBmux, \Y)) && port(ffBmux, BA).extract(offset, GetSize(sigffBmuxY)) == sigffBmuxY define pol (BA == \B) set ffBenpol pol - semioptional + optional endmatch match ffMmux @@ -180,10 +180,8 @@ code clock sigM sigP reject; SigBit c = port(ffM, \CLK).as_bit(); - if (clock != SigBit() && c != clock) reject; - clock = c; } // Cannot have ffMmux enable mux without ffM @@ -198,6 +196,8 @@ match postAdd if port(dsp, \OPMODE).extract(4,3).is_fully_zero() select postAdd->type.in($add) + select GetSize(port(postAdd, \Y)) <= 48 + select nusers(port(postAdd, \Y)) == 2 choice AB {\A, \B} select nusers(port(postAdd, AB)) <= 3 filter ffMmux || nusers(port(postAdd, AB)) == 2 @@ -256,6 +256,7 @@ match ffP select ffP->type.in($dff) // DSP48E1 does not support clock inversion select param(ffP, \CLK_POLARITY).as_bool() + select nusers(port(ffP, \D)) == 2 filter GetSize(port(ffP, \D)) >= GetSize(sigP) slice offset GetSize(port(ffP, \D)) filter offset+GetSize(sigP) <= GetSize(port(ffP, \D)) && port(ffP, \D).extract(offset, GetSize(sigP)) == sigP -- cgit v1.2.3 From 39a5d046ea5fe1021520d285723ef0b02dca4d17 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 11:38:19 -0700 Subject: Fix nusers condition in ffP --- passes/pmgen/xilinx_dsp.pmg | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index bb3bf90bd..adf30b45a 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -228,6 +228,8 @@ code sigC sigP endcode match ffPmux + if param(dsp, \PREG).as_int() == 0 + if nusers(sigP) == 2 select ffPmux->type.in($mux) choice BA {\B, \A} // new-value net must have exactly two users: dsp and ffP @@ -253,13 +255,14 @@ endcode match ffP if param(dsp, \PREG).as_int() == 0 + if nusers(sigP) == 2 select ffP->type.in($dff) // DSP48E1 does not support clock inversion select param(ffP, \CLK_POLARITY).as_bool() - select nusers(port(ffP, \D)) == 2 filter GetSize(port(ffP, \D)) >= GetSize(sigP) slice offset GetSize(port(ffP, \D)) - filter offset+GetSize(sigP) <= GetSize(port(ffP, \D)) && port(ffP, \D).extract(offset, GetSize(sigP)) == sigP + filter offset+GetSize(sigP) <= GetSize(port(ffP, \D)) + filter port(ffP, \D).extract(offset, GetSize(sigP)) == sigP // Check ffPmux (when present) is a $dff enable mux filter !ffPmux || port(ffP, \Q) == port(ffPmux, ffPenpol ? \A : \B) optional -- cgit v1.2.3 From fbf1b749460dea32eb52c39a9553fc8fdfdd914e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 11:39:20 -0700 Subject: Simplify filter expressions --- passes/pmgen/xilinx_dsp.pmg | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index adf30b45a..a9e2ebf86 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -50,7 +50,8 @@ match ffA select param(ffA, \CLK_POLARITY).as_bool() filter GetSize(port(ffA, \Q)) >= GetSize(sigA) slice offset GetSize(port(ffA, \Q)) - filter offset+GetSize(sigA) <= GetSize(port(ffA, \Q)) && port(ffA, \Q).extract(offset, GetSize(sigA)) == sigA + filter offset+GetSize(sigA) <= GetSize(port(ffA, \Q)) + filter port(ffA, \Q).extract(offset, GetSize(sigA)) == sigA optional endmatch @@ -78,9 +79,11 @@ match ffAmux select ffAmux->type.in($mux) filter GetSize(port(ffAmux, \Y)) >= GetSize(sigA) slice offset GetSize(port(ffAmux, \Y)) - filter offset+GetSize(sigA) <= GetSize(port(ffAmux, \Y)) && port(ffAmux, \Y).extract(offset, GetSize(sigA)) == sigA + filter offset+GetSize(sigA) <= GetSize(port(ffAmux, \Y)) + filter port(ffAmux, \Y).extract(offset, GetSize(sigA)) == sigA choice BA {\B, \A} - filter offset+GetSize(sigffAmuxY) <= GetSize(port(ffAmux, \Y)) && port(ffAmux, BA).extract(offset, GetSize(sigffAmuxY)) == sigffAmuxY + filter offset+GetSize(sigffAmuxY) <= GetSize(port(ffAmux, \Y)) + filter port(ffAmux, BA).extract(offset, GetSize(sigffAmuxY)) == sigffAmuxY define pol (BA == \B) set ffAenpol pol optional @@ -93,7 +96,8 @@ match ffB select param(ffB, \CLK_POLARITY).as_bool() filter GetSize(port(ffB, \Q)) >= GetSize(sigB) slice offset GetSize(port(ffB, \Q)) - filter offset+GetSize(sigB) <= GetSize(port(ffB, \Q)) && port(ffB, \Q).extract(offset, GetSize(sigB)) == sigB + filter offset+GetSize(sigB) <= GetSize(port(ffB, \Q)) + filter port(ffB, \Q).extract(offset, GetSize(sigB)) == sigB optional endmatch @@ -124,9 +128,11 @@ match ffBmux select ffBmux->type.in($mux) filter GetSize(port(ffBmux, \Y)) >= GetSize(sigB) slice offset GetSize(port(ffBmux, \Y)) - filter offset+GetSize(sigB) <= GetSize(port(ffBmux, \Y)) && port(ffBmux, \Y).extract(offset, GetSize(sigB)) == sigB + filter offset+GetSize(sigB) <= GetSize(port(ffBmux, \Y)) + filter port(ffBmux, \Y).extract(offset, GetSize(sigB)) == sigB choice BA {\B, \A} - filter offset+GetSize(sigffBmuxY) <= GetSize(port(ffBmux, \Y)) && port(ffBmux, BA).extract(offset, GetSize(sigffBmuxY)) == sigffBmuxY + filter offset+GetSize(sigffBmuxY) <= GetSize(port(ffBmux, \Y)) + filter port(ffBmux, BA).extract(offset, GetSize(sigffBmuxY)) == sigffBmuxY define pol (BA == \B) set ffBenpol pol optional -- cgit v1.2.3 From a945f6c7ef43258504f8c9c5a9c2d2e03fbfe0fe Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 11:58:56 -0700 Subject: Fix ffPmux to cope with offset --- passes/pmgen/xilinx_dsp.pmg | 46 +++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index a9e2ebf86..58ffcfedf 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -4,6 +4,7 @@ state clock state sigA sigffAmuxY sigB sigffBmuxY sigC sigM sigP state postAddAB postAddMuxAB state ffAenpol ffBenpol ffMenpol ffPenpol +state ffPoffset match dsp select dsp->type.in(\DSP48E1) @@ -139,6 +140,8 @@ match ffBmux endmatch match ffMmux + if param(dsp, \MREG).as_int() == 0 + if nusers(sigM) == 2 select ffMmux->type.in($mux) choice BA {\B, \A} // new-value net must have exactly two users: dsp and ffM @@ -164,6 +167,7 @@ endcode match ffM if param(dsp, \MREG).as_int() == 0 + if nusers(sigM) == 2 select ffM->type.in($dff) // DSP48E1 does not support clock inversion select param(ffM, \CLK_POLARITY).as_bool() @@ -235,31 +239,47 @@ endcode match ffPmux if param(dsp, \PREG).as_int() == 0 + // new-value net must have exactly two users: dsp and ffP if nusers(sigP) == 2 select ffPmux->type.in($mux) + // ffPmux output must have two users: ffPmux and ffP.D + select nusers(port(ffPmux, \Y)) == 2 + filter GetSize(port(ffPmux, \Y)) >= GetSize(sigP) + choice BA {\B, \A} - // new-value net must have exactly two users: dsp and ffP - select nusers(port(ffPmux, BA)) == 2 + slice offset GetSize(port(ffPmux, \Y)) + filter offset+GetSize(sigP) <= GetSize(port(ffPmux, \Y)) + filter port(ffPmux, BA).extract(offset, GetSize(sigP)) == sigP + define AB (BA == \B ? \A : \B) // keep-last-value net must have at least three users: ffPmux, ffP, downstream sink(s) - select nusers(port(ffPmux, AB)) >= 3 - // ffPmux output must have two users: ffPmux and ffP.D - select nusers(port(ffPmux, \Y)) == 2 - filter GetSize(port(ffPmux, \Y)) <= GetSize(sigP) - filter port(ffPmux, BA) == sigP.extract(0, GetSize(port(ffPmux, \Y))) - // Remaining bits on sigP must not have any other users - filter nusers(sigP.extract_end(GetSize(port(ffPmux, BA)))) <= 1 + filter nusers(port(ffPmux, AB)) >= 3 define pol (BA == \B) set ffPenpol pol + set ffPoffset offset optional endmatch code sigP if (ffPmux) - sigP.replace(port(ffPmux, ffPenpol ? \A : \B), port(ffPmux, \Y)); + sigP.replace(port(ffPmux, ffPenpol ? \B : \A), port(ffPmux, \Y)); endcode +match ffP_enable + if ffPmux + if nusers(sigP) == 2 + select ffP_enable->type.in($dff) + // DSP48E1 does not support clock inversion + select param(ffP_enable, \CLK_POLARITY).as_bool() + index port(ffP_enable, \D) === port(ffPmux, \Y) + index port(ffP_enable, \Q) === port(ffPmux, ffPenpol ? \A : \B) + filter GetSize(port(ffP_enable, \D)) >= GetSize(sigP) + filter ffPoffset+GetSize(sigP) <= GetSize(port(ffP_enable, \D)) + filter port(ffP_enable, \D).extract(ffPoffset, GetSize(sigP)) == sigP +endmatch + match ffP + if !ffP_enable if param(dsp, \PREG).as_int() == 0 if nusers(sigP) == 2 select ffP->type.in($dff) @@ -269,12 +289,14 @@ match ffP slice offset GetSize(port(ffP, \D)) filter offset+GetSize(sigP) <= GetSize(port(ffP, \D)) filter port(ffP, \D).extract(offset, GetSize(sigP)) == sigP - // Check ffPmux (when present) is a $dff enable mux - filter !ffPmux || port(ffP, \Q) == port(ffPmux, ffPenpol ? \A : \B) optional endmatch code ffP sigP clock + if (ffP_enable) { + log_assert(!ffP); + ffP = ffP_enable; + } if (ffP) { for (auto b : port(ffP, \Q)) if (b.wire->get_bool_attribute(\keep)) -- cgit v1.2.3 From 776d76994102af4ee9ade69392f31c0a2f4f61ce Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 12:07:35 -0700 Subject: Use more index patterns --- passes/pmgen/xilinx_dsp.pmg | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 58ffcfedf..5cea69b16 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -78,6 +78,7 @@ endcode match ffAmux if !sigffAmuxY.empty() select ffAmux->type.in($mux) + index port(ffAmux, \Y) === port(ffA, \D) filter GetSize(port(ffAmux, \Y)) >= GetSize(sigA) slice offset GetSize(port(ffAmux, \Y)) filter offset+GetSize(sigA) <= GetSize(port(ffAmux, \Y)) @@ -127,6 +128,7 @@ endcode match ffBmux if !sigffBmuxY.empty() select ffBmux->type.in($mux) + index port(ffBmux, \Y) === port(ffB, \D) filter GetSize(port(ffBmux, \Y)) >= GetSize(sigB) slice offset GetSize(port(ffBmux, \Y)) filter offset+GetSize(sigB) <= GetSize(port(ffBmux, \Y)) @@ -165,23 +167,32 @@ code sigM sigM = port(ffMmux, \Y); endcode +match ffM_enable + if ffMmux + if nusers(sigM) == 2 + select ffM_enable->type.in($dff) + // DSP48E1 does not support clock inversion + select param(ffM_enable, \CLK_POLARITY).as_bool() + index port(ffM_enable, \D) === sigM + index port(ffM_enable, \Q) === port(ffMmux, ffMenpol ? \A : \B) +endmatch + match ffM + if !ffM_enable if param(dsp, \MREG).as_int() == 0 if nusers(sigM) == 2 select ffM->type.in($dff) // DSP48E1 does not support clock inversion select param(ffM, \CLK_POLARITY).as_bool() - select nusers(port(ffM, \D)) == 2 - filter GetSize(port(ffM, \D)) <= GetSize(sigM) - filter port(ffM, \D) == sigM.extract(0, GetSize(port(ffM, \D))) - // Remaining bits on sigM must not have any other users - filter nusers(sigM.extract_end(GetSize(port(ffM, \D)))) <= 1 - // Check ffMmux (when present) is a $dff enable mux - filter !ffMmux || port(ffM, \Q) == port(ffMmux, ffMenpol ? \A : \B) + index port(ffM, \D) === sigM optional endmatch -code clock sigM sigP +code ffM clock sigM sigP + if (ffM_enable) { + log_assert(!ffM); + ffM = ffM_enable; + } if (ffM) { sigM = port(ffM, \Q); @@ -194,10 +205,6 @@ code clock sigM sigP reject; clock = c; } - // Cannot have ffMmux enable mux without ffM - else if (ffMmux) - reject; - sigP = sigM; endcode @@ -311,9 +318,6 @@ code ffP sigP clock sigP.replace(port(ffP, \D), port(ffP, \Q)); } - // Cannot have ffPmux enable mux without ffP - else if (ffPmux) - reject; endcode match postAddMux -- cgit v1.2.3 From da8fe83f7ac6305d6cc884823a561828b13e7931 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 12:16:40 -0700 Subject: Tidy up ice40_dsp some more --- passes/pmgen/ice40_dsp.cc | 6 +++--- passes/pmgen/ice40_dsp.pmg | 21 ++++++++++----------- 2 files changed, 13 insertions(+), 14 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 7858b8972..68fc29f31 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -219,10 +219,10 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam("\\B_SIGNED", st.mul->getParam("\\B_SIGNED").as_bool()); if (st.ffO) { - if (st.ffO_hilo) - cell->setParam("\\TOPOUTPUT_SELECT", Const(1, 2)); - else + if (st.ffO_lo) cell->setParam("\\TOPOUTPUT_SELECT", Const(st.addAB ? 0 : 3, 2)); + else + cell->setParam("\\TOPOUTPUT_SELECT", Const(1, 2)); st.ffO->connections_.at("\\Q").replace(O, pm.module->addWire(NEW_ID, GetSize(O))); cell->setParam("\\BOTOUTPUT_SELECT", Const(1, 2)); diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 95e8da379..fbf498109 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -3,7 +3,7 @@ pattern ice40_dsp state clock state clock_pol cd_signed state sigA sigB sigCD sigH sigO -state addAB muxAB ffO +state addAB muxAB match mul select mul->type.in($mul, \SB_MAC16) @@ -202,21 +202,21 @@ code muxAB sigO sigO = port(muxAB, \Y); endcode -match ffO_hilo +match ffO // Ensure that register is not already used if mul->type != \SB_MAC16 || (mul->parameters.at(\TOPOUTPUT_SELECT, 0).as_int() != 1 && mul->parameters.at(\BOTOUTPUT_SELECT, 0).as_int() != 1) // Ensure that OLOADTOP/OLOADBOT is unused or zero if mul->type != \SB_MAC16 || (mul->connections_.at(\OLOADTOP, State::S0).is_fully_zero() && mul->connections_.at(\OLOADBOT, State::S0).is_fully_zero()) if nusers(sigO) == 2 - select ffO_hilo->type.in($dff) - filter GetSize(port(ffO_hilo, \D)) >= GetSize(sigO) - slice offset GetSize(port(ffO_hilo, \D)) - filter offset+GetSize(sigO) <= GetSize(port(ffO_hilo, \D)) && port(ffO_hilo, \D).extract(offset, GetSize(sigO)) == sigO + select ffO->type.in($dff) + filter GetSize(port(ffO, \D)) >= GetSize(sigO) + slice offset GetSize(port(ffO, \D)) + filter offset+GetSize(sigO) <= GetSize(port(ffO, \D)) && port(ffO, \D).extract(offset, GetSize(sigO)) == sigO optional endmatch match ffO_lo - if !ffO_hilo && GetSize(sigO) > 16 + if !ffO && GetSize(sigO) > 16 // Ensure that register is not already used if mul->type != \SB_MAC16 || (mul->parameters.at(\TOPOUTPUT_SELECT, 0).as_int() != 1 && mul->parameters.at(\BOTOUTPUT_SELECT, 0).as_int() != 1) // Ensure that OLOADTOP/OLOADBOT is unused or zero @@ -230,11 +230,10 @@ match ffO_lo endmatch code ffO clock clock_pol sigO sigCD cd_signed - ffO = nullptr; - if (ffO_hilo) - ffO = ffO_hilo; - else if (ffO_lo) + if (ffO_lo) { + log_assert(!ffO); ffO = ffO_lo; + } if (ffO) { for (auto b : port(ffO, \Q)) if (b.wire->get_bool_attribute(\keep)) -- cgit v1.2.3 From ef77162ce4bff9987312a0881483c7befaed2dc5 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 13:28:15 -0700 Subject: Document (* gentb_skip *) attr for test_autotb --- passes/tests/test_autotb.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'passes') diff --git a/passes/tests/test_autotb.cc b/passes/tests/test_autotb.cc index 7f11e54f3..2b6a86c25 100644 --- a/passes/tests/test_autotb.cc +++ b/passes/tests/test_autotb.cc @@ -345,6 +345,9 @@ struct TestAutotbBackend : public Backend { log("value after initialization. This can e.g. be used to force a reset signal\n"); log("low in order to explore more inner states in a state machine.\n"); log("\n"); + log("The attribute 'gentb_skip' can be attached to modules to suppress testbench\n"); + log("generation.\n"); + log("\n"); log(" -n \n"); log(" number of iterations the test bench should run (default = 1000)\n"); log("\n"); -- cgit v1.2.3 From e926f2973e5c6bf8e00cd67fc44200ceb47e215e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 14:06:57 -0700 Subject: Add support for pre-adder and AD register --- passes/pmgen/xilinx_dsp.cc | 31 +++++++++++++- passes/pmgen/xilinx_dsp.pmg | 101 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 128 insertions(+), 4 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 38b1a12be..9587ed28a 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -31,6 +31,9 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) #if 1 log("\n"); + log("preAdd: %s\n", log_id(st.preAdd, "--")); + log("ffAD: %s\n", log_id(st.ffAD, "--")); + log("ffADmux: %s\n", log_id(st.ffADmux, "--")); log("ffA: %s\n", log_id(st.ffA, "--")); log("ffAmux: %s\n", log_id(st.ffAmux, "--")); log("ffB: %s\n", log_id(st.ffB, "--")); @@ -51,8 +54,34 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) SigSpec C = st.sigC; SigSpec P = st.sigP; + if (st.preAdd) { + log(" preadder %s (%s)\n", log_id(st.preAdd), log_id(st.preAdd->type)); + bool A_SIGNED = st.preAdd->getParam("\\A_SIGNED").as_bool(); + bool D_SIGNED = st.preAdd->getParam("\\B_SIGNED").as_bool(); + if (st.sigA == st.preAdd->getPort("\\B")) + std::swap(A_SIGNED, D_SIGNED); + st.sigA.extend_u0(30, A_SIGNED); + st.sigD.extend_u0(25, D_SIGNED); + cell->setPort("\\A", st.sigA); + cell->setPort("\\D", st.sigD); + cell->connections_.at("\\INMODE") = Const::from_string("00100"); + + if (st.ffAD) { + if (st.ffADmux) { + SigSpec S = st.ffADmux->getPort("\\S"); + cell->setPort("\\CEAD", st.ffADenpol ? S : pm.module->Not(NEW_ID, S)); + } + else + cell->setPort("\\CEAD", State::S1); + cell->setParam("\\ADREG", 1); + } + + cell->setParam("\\USE_DPORT", Const("TRUE")); + + pm.autoremove(st.preAdd); + } if (st.postAdd) { - log(" adder %s (%s)\n", log_id(st.postAdd), log_id(st.postAdd->type)); + log(" postadder %s (%s)\n", log_id(st.postAdd), log_id(st.postAdd->type)); SigSpec &opmode = cell->connections_.at("\\OPMODE"); if (st.postAddMux) { diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 5cea69b16..83963804b 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,16 +1,16 @@ pattern xilinx_dsp state clock -state sigA sigffAmuxY sigB sigffBmuxY sigC sigM sigP +state sigA sigffAmuxY sigB sigffBmuxY sigC sigD sigM sigP state postAddAB postAddMuxAB -state ffAenpol ffBenpol ffMenpol ffPenpol +state ffAenpol ffADenpol ffBenpol ffMenpol ffPenpol state ffPoffset match dsp select dsp->type.in(\DSP48E1) endmatch -code sigA sigffAmuxY sigB sigffBmuxY sigM +code sigA sigffAmuxY sigB sigffBmuxY sigD sigM sigA = port(dsp, \A); int i; for (i = GetSize(sigA)-1; i > 0; i--) @@ -29,6 +29,8 @@ code sigA sigffAmuxY sigB sigffBmuxY sigM ++i; sigB.remove(i, GetSize(sigB)-i); + sigD = dsp->connections_.at(\D, SigSpec()); + SigSpec P = port(dsp, \P); // Only care about those bits that are used for (i = 0; i < GetSize(P); i++) { @@ -44,7 +46,85 @@ code sigA sigffAmuxY sigB sigffBmuxY sigM sigffBmuxY = SigSpec(); endcode +match ffAD + if param(dsp, \ADREG).as_int() == 0 + select ffAD->type.in($dff) + // DSP48E1 does not support clock inversion + select param(ffAD, \CLK_POLARITY).as_bool() + filter GetSize(port(ffAD, \Q)) >= GetSize(sigA) + slice offset GetSize(port(ffAD, \Q)) + filter offset+GetSize(sigA) <= GetSize(port(ffAD, \Q)) + filter port(ffAD, \Q).extract(offset, GetSize(sigA)) == sigA + optional +endmatch + +code sigA sigffAmuxY clock + if (ffAD) { + for (auto b : port(ffAD, \Q)) + if (b.wire->get_bool_attribute(\keep)) + reject; + + clock = port(ffAD, \CLK).as_bit(); + + SigSpec A = sigA; + A.replace(port(ffAD, \Q), port(ffAD, \D)); + // Only search for ffAmux if ffA.Q has at + // least 3 users (ffA, dsp, ffAmux) and + // its ffA.D only has two (ffA, ffAmux) + if (nusers(sigA) >= 3 && nusers(A) == 2) + sigffAmuxY = sigA; + sigA = std::move(A); + } +endcode + +match ffADmux + if !sigffAmuxY.empty() + select ffADmux->type.in($mux) + index port(ffADmux, \Y) === port(ffAD, \D) + filter GetSize(port(ffADmux, \Y)) >= GetSize(sigA) + slice offset GetSize(port(ffADmux, \Y)) + filter offset+GetSize(sigA) <= GetSize(port(ffADmux, \Y)) + filter port(ffADmux, \Y).extract(offset, GetSize(sigA)) == sigA + choice BA {\B, \A} + filter offset+GetSize(sigffAmuxY) <= GetSize(port(ffADmux, \Y)) + filter port(ffADmux, BA).extract(offset, GetSize(sigffAmuxY)) == sigffAmuxY + define pol (BA == \B) + set ffADenpol pol + optional +endmatch + +match preAdd + if sigD.empty() || sigD.is_fully_zero() + // Ensure that preAdder not already used + if dsp->parameters.at(\USE_DPORT, Const("FALSE")).decode_string() == "FALSE" + if dsp->connections_.at(\INMODE, Const(0, 5)).is_fully_zero() + + select preAdd->type.in($add) + // Output has to be 25 bits or less + select GetSize(port(preAdd, \Y)) <= 25 + select nusers(port(preAdd, \Y)) == 2 + choice AB {\A, \B} + // A port has to be 30 bits or less + select GetSize(port(preAdd, AB)) <= 30 + define BA (AB == \A ? \B : \A) + // D port has to be 25 bits or less + select GetSize(port(preAdd, BA)) <= 25 + index port(preAdd, \Y) === sigA + + optional +endmatch + +code sigA sigD + if (preAdd) { + sigA = port(preAdd, \A); + sigD = port(preAdd, \B); + if (GetSize(sigA) < GetSize(sigD)) + std::swap(sigA, sigD); + } +endcode + match ffA + if !preAdd if param(dsp, \AREG).as_int() == 0 select ffA->type.in($dff) // DSP48E1 does not support clock inversion @@ -73,6 +153,9 @@ code sigA sigffAmuxY clock sigffAmuxY = sigA; sigA = std::move(A); } + else if (!preAdd) { + sigffAmuxY = SigSpec(); + } endcode match ffAmux @@ -91,6 +174,18 @@ match ffAmux optional endmatch +code ffA ffAmux ffAenpol ffAD ffADmux + // Move AD register to A if no pre-adder + if (!ffA && !preAdd && ffAD) { + ffA = ffAD; + ffAmux = ffADmux; + ffAenpol = ffADenpol; + + ffAD = nullptr; + ffADmux = nullptr; + } +endcode + match ffB if param(dsp, \BREG).as_int() == 0 select ffB->type.in($dff) -- cgit v1.2.3 From 2c32056990b9742839841f4cf3fa31d742cef472 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 14:10:12 -0700 Subject: Logging for ffAD --- passes/pmgen/xilinx_dsp.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 9587ed28a..65a4d5a11 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -177,6 +177,9 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) if (st.ffA) log(" ffA:%s", log_id(st.ffA)); + if (st.ffAD) + log(" ffAD:%s", log_id(st.ffAD)); + if (st.ffB) log(" ffB:%s", log_id(st.ffB)); -- cgit v1.2.3 From 8246062acfd3b294c59ce72a9dcc6513dc0d08bd Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 14:36:10 -0700 Subject: Fix enable polarity --- passes/pmgen/xilinx_dsp.cc | 4 ++-- passes/pmgen/xilinx_dsp.pmg | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 65a4d5a11..d8213e02f 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -112,7 +112,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) A.replace(Q, D); if (st.ffAmux) { SigSpec Y = st.ffAmux->getPort("\\Y"); - SigSpec AB = st.ffAmux->getPort(st.ffAenpol ? "\\A" : "\\B"); + SigSpec AB = st.ffAmux->getPort(st.ffAenpol ? "\\B" : "\\A"); SigSpec S = st.ffAmux->getPort("\\S"); A.replace(Y, AB); cell->setPort("\\CEA2", st.ffAenpol ? S : pm.module->Not(NEW_ID, S)); @@ -130,7 +130,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) B.replace(Q, D); if (st.ffBmux) { SigSpec Y = st.ffBmux->getPort("\\Y"); - SigSpec AB = st.ffBmux->getPort(st.ffBenpol ? "\\A" : "\\B"); + SigSpec AB = st.ffBmux->getPort(st.ffBenpol ? "\\B" : "\\A"); SigSpec S = st.ffBmux->getPort("\\S"); B.replace(Y, AB); cell->setPort("\\CEB2", st.ffBenpol ? S : pm.module->Not(NEW_ID, S)); diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 83963804b..f8bd26e8b 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -85,10 +85,10 @@ match ffADmux slice offset GetSize(port(ffADmux, \Y)) filter offset+GetSize(sigA) <= GetSize(port(ffADmux, \Y)) filter port(ffADmux, \Y).extract(offset, GetSize(sigA)) == sigA - choice BA {\B, \A} + choice AB {\A, \B} filter offset+GetSize(sigffAmuxY) <= GetSize(port(ffADmux, \Y)) - filter port(ffADmux, BA).extract(offset, GetSize(sigffAmuxY)) == sigffAmuxY - define pol (BA == \B) + filter port(ffADmux, AB).extract(offset, GetSize(sigffAmuxY)) == sigffAmuxY + define pol (AB == \A) set ffADenpol pol optional endmatch @@ -166,10 +166,10 @@ match ffAmux slice offset GetSize(port(ffAmux, \Y)) filter offset+GetSize(sigA) <= GetSize(port(ffAmux, \Y)) filter port(ffAmux, \Y).extract(offset, GetSize(sigA)) == sigA - choice BA {\B, \A} + choice AB {\A, \B} filter offset+GetSize(sigffAmuxY) <= GetSize(port(ffAmux, \Y)) - filter port(ffAmux, BA).extract(offset, GetSize(sigffAmuxY)) == sigffAmuxY - define pol (BA == \B) + filter port(ffAmux, AB).extract(offset, GetSize(sigffAmuxY)) == sigffAmuxY + define pol (AB == \A) set ffAenpol pol optional endmatch @@ -228,10 +228,10 @@ match ffBmux slice offset GetSize(port(ffBmux, \Y)) filter offset+GetSize(sigB) <= GetSize(port(ffBmux, \Y)) filter port(ffBmux, \Y).extract(offset, GetSize(sigB)) == sigB - choice BA {\B, \A} + choice AB {\A, \B} filter offset+GetSize(sigffBmuxY) <= GetSize(port(ffBmux, \Y)) - filter port(ffBmux, BA).extract(offset, GetSize(sigffBmuxY)) == sigffBmuxY - define pol (BA == \B) + filter port(ffBmux, AB).extract(offset, GetSize(sigffBmuxY)) == sigffBmuxY + define pol (AB == \A) set ffBenpol pol optional endmatch @@ -252,7 +252,7 @@ match ffMmux filter port(ffMmux, BA) == sigM.extract(0, GetSize(port(ffMmux, \Y))) // Remaining bits on sigM must not have any other users filter nusers(sigM.extract_end(GetSize(port(ffMmux, BA)))) <= 1 - define pol (BA == \B) + define pol (AB == \A) set ffMenpol pol optional endmatch @@ -348,15 +348,15 @@ match ffPmux select nusers(port(ffPmux, \Y)) == 2 filter GetSize(port(ffPmux, \Y)) >= GetSize(sigP) - choice BA {\B, \A} slice offset GetSize(port(ffPmux, \Y)) filter offset+GetSize(sigP) <= GetSize(port(ffPmux, \Y)) + choice BA {\B, \A} filter port(ffPmux, BA).extract(offset, GetSize(sigP)) == sigP define AB (BA == \B ? \A : \B) // keep-last-value net must have at least three users: ffPmux, ffP, downstream sink(s) filter nusers(port(ffPmux, AB)) >= 3 - define pol (BA == \B) + define pol (AB == \A) set ffPenpol pol set ffPoffset offset optional -- cgit v1.2.3 From 0d1d8b4d24d3cce071e7c7e3c6284ba2cb874bd0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 14:57:36 -0700 Subject: Fix macc and mul tests --- passes/pmgen/xilinx_dsp.pmg | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index f8bd26e8b..d91072868 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -300,6 +300,10 @@ code ffM clock sigM sigP reject; clock = c; } + // No enable mux possible without flop + else if (ffMmux) + reject; + sigP = sigM; endcode @@ -341,8 +345,11 @@ endcode match ffPmux if param(dsp, \PREG).as_int() == 0 - // new-value net must have exactly two users: dsp and ffP - if nusers(sigP) == 2 + // If ffMmux, new-value net must have exactly three users: ffMmux, ffM and ffPmux + if !ffMmux || nusers(sigP) == 3 + // Otherwise new-value net must have exactly two users: dsp and ffPmux + if ffMmux || nusers(sigP) == 2 + select ffPmux->type.in($mux) // ffPmux output must have two users: ffPmux and ffP.D select nusers(port(ffPmux, \Y)) == 2 @@ -383,7 +390,11 @@ endmatch match ffP if !ffP_enable if param(dsp, \PREG).as_int() == 0 - if nusers(sigP) == 2 + // If ffMmux, input net must have exactly three users: ffMmux, ffM and ffP + if !ffMmux || nusers(sigP) == 3 + // Otherwise input net must have exactly two users: dsp and ffP + if ffMmux || nusers(sigP) == 2 + select ffP->type.in($dff) // DSP48E1 does not support clock inversion select param(ffP, \CLK_POLARITY).as_bool() @@ -413,6 +424,9 @@ code ffP sigP clock sigP.replace(port(ffP, \D), port(ffP, \Q)); } + // No enable mux possible without flop + else if (ffPmux) + reject; endcode match postAddMux -- cgit v1.2.3 From ef56f8596fdd9753e93dbd654493497be8902691 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 15:11:41 -0700 Subject: Fine tune nusers when postAdd --- passes/pmgen/xilinx_dsp.pmg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index d91072868..7d943b16f 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -345,10 +345,10 @@ endcode match ffPmux if param(dsp, \PREG).as_int() == 0 - // If ffMmux, new-value net must have exactly three users: ffMmux, ffM and ffPmux - if !ffMmux || nusers(sigP) == 3 + // If ffMmux and no postAdd new-value net must have exactly three users: ffMmux, ffM and ffPmux + if !ffMmux || postAdd || nusers(sigP) == 3 // Otherwise new-value net must have exactly two users: dsp and ffPmux - if ffMmux || nusers(sigP) == 2 + if (ffMmux && !postAdd) || nusers(sigP) == 2 select ffPmux->type.in($mux) // ffPmux output must have two users: ffPmux and ffP.D -- cgit v1.2.3 From 74eac766995237dec86d51778811cf186c68d851 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 15:32:26 -0700 Subject: Add support for DREG --- passes/pmgen/xilinx_dsp.cc | 13 ++++++++++ passes/pmgen/xilinx_dsp.pmg | 59 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 70 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index d8213e02f..547073aa6 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -38,6 +38,8 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("ffAmux: %s\n", log_id(st.ffAmux, "--")); log("ffB: %s\n", log_id(st.ffB, "--")); log("ffBmux: %s\n", log_id(st.ffBmux, "--")); + log("ffD: %s\n", log_id(st.ffD, "--")); + log("ffDmux: %s\n", log_id(st.ffDmux, "--")); log("dsp: %s\n", log_id(st.dsp, "--")); log("ffM: %s\n", log_id(st.ffM, "--")); log("ffMmux: %s\n", log_id(st.ffMmux, "--")); @@ -141,6 +143,17 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) cell->setParam("\\BREG", 1); } + if (st.ffD) { + if (st.ffDmux) { + SigSpec S = st.ffDmux->getPort("\\S"); + cell->setPort("\\CED", st.ffBenpol ? S : pm.module->Not(NEW_ID, S)); + } + else + cell->setPort("\\CED", State::S1); + cell->setPort("\\D", st.sigD); + + cell->setParam("\\DREG", 1); + } if (st.ffM) { if (st.ffMmux) { SigSpec S = st.ffMmux->getPort("\\S"); diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 7d943b16f..6cc42e2e1 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,9 +1,9 @@ pattern xilinx_dsp state clock -state sigA sigffAmuxY sigB sigffBmuxY sigC sigD sigM sigP +state sigA sigffAmuxY sigB sigffBmuxY sigC sigD sigffDmuxY sigM sigP state postAddAB postAddMuxAB -state ffAenpol ffADenpol ffBenpol ffMenpol ffPenpol +state ffAenpol ffADenpol ffBenpol ffDenpol ffMenpol ffPenpol state ffPoffset match dsp @@ -236,6 +236,61 @@ match ffBmux optional endmatch +match ffD + if param(dsp, \DREG).as_int() == 0 + select ffD->type.in($dff) + // DSP48E1 does not support clock inversion + select param(ffD, \CLK_POLARITY).as_bool() + filter GetSize(port(ffD, \Q)) >= GetSize(sigD) + slice offset GetSize(port(ffD, \Q)) + filter offset+GetSize(sigD) <= GetSize(port(ffD, \Q)) + filter port(ffD, \Q).extract(offset, GetSize(sigD)) == sigD + optional +endmatch + +code sigD sigffDmuxY clock + if (ffD) { + for (auto b : port(ffD, \Q)) + if (b.wire->get_bool_attribute(\keep)) + reject; + + SigBit c = port(ffD, \CLK).as_bit(); + if (clock != SigBit() && c != clock) + reject; + clock = c; + + SigSpec D = sigD; + D.replace(port(ffD, \Q), port(ffD, \D)); + // Only search for ffBmux if ffB.Q has at + // least 3 users (ffB, dsp, ffBmux) and + // its ffB.D only has two (ffB, ffBmux) + if (nusers(sigD) >= 3 && nusers(D) == 2) + sigffDmuxY = sigD; + sigD = std::move(D); + } +endcode + +match ffDmux + if !sigffDmuxY.empty() + select ffDmux->type.in($mux) + index port(ffDmux, \Y) === port(ffD, \D) + filter GetSize(port(ffDmux, \Y)) >= GetSize(sigD) + slice offset GetSize(port(ffDmux, \Y)) + filter offset+GetSize(sigD) <= GetSize(port(ffDmux, \Y)) + filter port(ffDmux, \Y).extract(offset, GetSize(sigB)) == sigD + choice AB {\A, \B} + filter offset+GetSize(sigffDmuxY) <= GetSize(port(ffDmux, \Y)) + filter port(ffDmux, AB).extract(offset, GetSize(sigffDmuxY)) == sigffDmuxY + define pol (AB == \A) + set ffDenpol pol + optional +endmatch + +code sigD + if (ffDmux) + sigD.replace(port(ffDmux, \Y), port(ffDmux, ffDenpol ? \B : \A)); +endcode + match ffMmux if param(dsp, \MREG).as_int() == 0 if nusers(sigM) == 2 -- cgit v1.2.3 From 5344bfe637e0c8d527f94f615e4ed8704c358cf8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 15:46:15 -0700 Subject: Perform D replacement properly --- passes/pmgen/xilinx_dsp.cc | 13 +++++++++++-- passes/pmgen/xilinx_dsp.pmg | 5 ----- 2 files changed, 11 insertions(+), 7 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 547073aa6..ba8a1de05 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -144,13 +144,22 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) cell->setParam("\\BREG", 1); } if (st.ffD) { + SigSpec D_ = cell->getPort("\\D"); + SigSpec D = st.ffB->getPort("\\D"); + SigSpec Q = st.ffB->getPort("\\Q"); + D_.replace(Q, D); + if (st.ffDmux) { + SigSpec Y = st.ffDmux->getPort("\\Y"); + SigSpec AB = st.ffDmux->getPort(st.ffDenpol ? "\\B" : "\\A"); SigSpec S = st.ffDmux->getPort("\\S"); - cell->setPort("\\CED", st.ffBenpol ? S : pm.module->Not(NEW_ID, S)); + D_.replace(Y, AB); + + cell->setPort("\\CED", st.ffDenpol ? S : pm.module->Not(NEW_ID, S)); } else cell->setPort("\\CED", State::S1); - cell->setPort("\\D", st.sigD); + cell->setPort("\\D", D_); cell->setParam("\\DREG", 1); } diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 6cc42e2e1..9e4738c88 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -286,11 +286,6 @@ match ffDmux optional endmatch -code sigD - if (ffDmux) - sigD.replace(port(ffDmux, \Y), port(ffDmux, ffDenpol ? \B : \A)); -endcode - match ffMmux if param(dsp, \MREG).as_int() == 0 if nusers(sigM) == 2 -- cgit v1.2.3 From b69512a5b90a854a96b6e25bf4ccc567a7f89ad2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 15:51:21 -0700 Subject: Fix ffP just like ffPmux --- passes/pmgen/xilinx_dsp.pmg | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 9e4738c88..7be841ff3 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -440,10 +440,10 @@ endmatch match ffP if !ffP_enable if param(dsp, \PREG).as_int() == 0 - // If ffMmux, input net must have exactly three users: ffMmux, ffM and ffP - if !ffMmux || nusers(sigP) == 3 - // Otherwise input net must have exactly two users: dsp and ffP - if ffMmux || nusers(sigP) == 2 + // If ffMmux and no postAdd new-value net must have exactly three users: ffMmux, ffM and ffPmux + if !ffMmux || postAdd || nusers(sigP) == 3 + // Otherwise new-value net must have exactly two users: dsp and ffPmux + if (ffMmux && !postAdd) || nusers(sigP) == 2 select ffP->type.in($dff) // DSP48E1 does not support clock inversion -- cgit v1.2.3 From 6a9205280f4c574db3a779e2f057e8649fe35356 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 18:40:11 -0700 Subject: Use unextend lambda --- passes/pmgen/xilinx_dsp.pmg | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 7be841ff3..3aab807bd 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,5 +1,6 @@ pattern xilinx_dsp +state > unextend state clock state sigA sigffAmuxY sigB sigffBmuxY sigC sigD sigffDmuxY sigM sigP state postAddAB postAddMuxAB @@ -10,29 +11,26 @@ match dsp select dsp->type.in(\DSP48E1) endmatch -code sigA sigffAmuxY sigB sigffBmuxY sigD sigM - sigA = port(dsp, \A); - int i; - for (i = GetSize(sigA)-1; i > 0; i--) - if (sigA[i] != sigA[i-1]) - break; - // Do not remove non-const sign bit - if (sigA[i].wire) - ++i; - sigA.remove(i, GetSize(sigA)-i); - sigB = port(dsp, \B); - for (i = GetSize(sigB)-1; i > 0; i--) - if (sigB[i] != sigB[i-1]) - break; - // Do not remove non-const sign bit - if (sigB[i].wire) - ++i; - sigB.remove(i, GetSize(sigB)-i); - +code unextend sigA sigffAmuxY sigB sigffBmuxY sigC sigD sigffDmuxY sigM + unextend = [](const SigSpec &sig, bool keep_sign) { + int i; + for (i = GetSize(sig)-1; i > 0; i--) + if (sig[i] != sig[i-1]) + break; + // Do not remove non-const sign bit + if (!keep_sign && sig[i].wire) + ++i; + return sig.extract(0, i); + }; + sigA = unextend(port(dsp, \A), false); + sigB = unextend(port(dsp, \B), false); + + sigC = dsp->connections_.at(\C, SigSpec()); sigD = dsp->connections_.at(\D, SigSpec()); SigSpec P = port(dsp, \P); // Only care about those bits that are used + int i; for (i = 0; i < GetSize(P); i++) { if (nusers(P[i]) <= 1) break; @@ -44,6 +42,7 @@ code sigA sigffAmuxY sigB sigffBmuxY sigD sigM sigffAmuxY = SigSpec(); sigffBmuxY = SigSpec(); + sigffDmuxY = SigSpec(); endcode match ffAD -- cgit v1.2.3 From 74a5c802f70c181520ce762376e9673a5f6f6465 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 21:01:36 -0700 Subject: Pack CREG --- passes/pmgen/xilinx_dsp.cc | 53 +++++++++++++++++++++------ passes/pmgen/xilinx_dsp.pmg | 89 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 111 insertions(+), 31 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index ba8a1de05..10308de57 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -38,6 +38,8 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("ffAmux: %s\n", log_id(st.ffAmux, "--")); log("ffB: %s\n", log_id(st.ffB, "--")); log("ffBmux: %s\n", log_id(st.ffBmux, "--")); + log("ffC: %s\n", log_id(st.ffC, "--")); + log("ffCmux: %s\n", log_id(st.ffCmux, "--")); log("ffD: %s\n", log_id(st.ffD, "--")); log("ffDmux: %s\n", log_id(st.ffDmux, "--")); log("dsp: %s\n", log_id(st.dsp, "--")); @@ -53,7 +55,6 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) Cell *cell = st.dsp; bit_to_driver.insert(std::make_pair(cell->getPort("\\P")[17], cell)); - SigSpec C = st.sigC; SigSpec P = st.sigP; if (st.preAdd) { @@ -91,15 +92,21 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) opmode[4] = st.postAddMux->getPort("\\S"); pm.autoremove(st.postAddMux); } - else if (st.ffP && C == P) { - C = SigSpec(); + else if (st.ffP && st.sigC == P) opmode[4] = State::S0; - } else opmode[4] = State::S1; opmode[6] = State::S0; opmode[5] = State::S1; + if (opmode[4] != State::S0) { + if (st.postAddMuxAB == "\\A") + st.sigC.extend_u0(48, st.postAdd->getParam("\\B_SIGNED").as_bool()); + else + st.sigC.extend_u0(48, st.postAdd->getParam("\\A_SIGNED").as_bool()); + cell->setPort("\\C", st.sigC); + } + pm.autoremove(st.postAdd); } @@ -143,10 +150,30 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) cell->setParam("\\BREG", 1); } + if (st.ffC) { + SigSpec C = cell->getPort("\\C"); + SigSpec D = st.ffC->getPort("\\D"); + SigSpec Q = st.ffC->getPort("\\Q"); + C.replace(Q, D); + + if (st.ffCmux) { + SigSpec Y = st.ffCmux->getPort("\\Y"); + SigSpec AB = st.ffCmux->getPort(st.ffCenpol ? "\\B" : "\\A"); + SigSpec S = st.ffCmux->getPort("\\S"); + C.replace(Y, AB); + + cell->setPort("\\CEC", st.ffCenpol ? S : pm.module->Not(NEW_ID, S)); + } + else + cell->setPort("\\CEC", State::S1); + cell->setPort("\\C", C); + + cell->setParam("\\CREG", 1); + } if (st.ffD) { SigSpec D_ = cell->getPort("\\D"); - SigSpec D = st.ffB->getPort("\\D"); - SigSpec Q = st.ffB->getPort("\\Q"); + SigSpec D = st.ffD->getPort("\\D"); + SigSpec Q = st.ffD->getPort("\\Q"); D_.replace(Q, D); if (st.ffDmux) { @@ -205,6 +232,12 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) if (st.ffB) log(" ffB:%s", log_id(st.ffB)); + if (st.ffC) + log(" ffC:%s", log_id(st.ffC)); + + if (st.ffD) + log(" ffD:%s", log_id(st.ffD)); + if (st.ffM) log(" ffM:%s", log_id(st.ffM)); @@ -214,12 +247,6 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("\n"); } - if (!C.empty()) { - if (GetSize(C) < 48) - C.extend_u0(48, true); - cell->setPort("\\C", C); - } - if (GetSize(P) < 48) P.append(pm.module->addWire(NEW_ID, 48-GetSize(P))); cell->setPort("\\P", P); @@ -265,6 +292,8 @@ struct XilinxDspPass : public Pass { for (auto cell : module->cells()) { if (cell->type != "\\DSP48E1") continue; + if (cell->parameters.at("\\CREG", State::S1).as_bool()) + continue; SigSpec &opmode = cell->connections_.at("\\OPMODE"); if (opmode.extract(4,3) != Const::from_string("011")) continue; diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 3aab807bd..6b981bc13 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,29 +1,29 @@ pattern xilinx_dsp -state > unextend +state > unextend state clock -state sigA sigffAmuxY sigB sigffBmuxY sigC sigD sigffDmuxY sigM sigP +state sigA sigffAmuxY sigB sigffBmuxY sigC sigffCmuxY sigD sigffDmuxY sigM sigP state postAddAB postAddMuxAB -state ffAenpol ffADenpol ffBenpol ffDenpol ffMenpol ffPenpol +state ffAenpol ffADenpol ffBenpol ffCenpol ffDenpol ffMenpol ffPenpol state ffPoffset match dsp select dsp->type.in(\DSP48E1) endmatch -code unextend sigA sigffAmuxY sigB sigffBmuxY sigC sigD sigffDmuxY sigM - unextend = [](const SigSpec &sig, bool keep_sign) { +code unextend sigA sigffAmuxY sigB sigffBmuxY sigC sigffCmuxY sigD sigffDmuxY sigM + unextend = [](const SigSpec &sig) { int i; for (i = GetSize(sig)-1; i > 0; i--) if (sig[i] != sig[i-1]) break; // Do not remove non-const sign bit - if (!keep_sign && sig[i].wire) + if (sig[i].wire) ++i; return sig.extract(0, i); }; - sigA = unextend(port(dsp, \A), false); - sigB = unextend(port(dsp, \B), false); + sigA = unextend(port(dsp, \A)); + sigB = unextend(port(dsp, \B)); sigC = dsp->connections_.at(\C, SigSpec()); sigD = dsp->connections_.at(\D, SigSpec()); @@ -42,6 +42,7 @@ code unextend sigA sigffAmuxY sigB sigffBmuxY sigC sigD sigffDmuxY sigM sigffAmuxY = SigSpec(); sigffBmuxY = SigSpec(); + sigffCmuxY = SigSpec(); sigffDmuxY = SigSpec(); endcode @@ -260,9 +261,9 @@ code sigD sigffDmuxY clock SigSpec D = sigD; D.replace(port(ffD, \Q), port(ffD, \D)); - // Only search for ffBmux if ffB.Q has at - // least 3 users (ffB, dsp, ffBmux) and - // its ffB.D only has two (ffB, ffBmux) + // Only search for ffDmux if ffD.Q has at + // least 3 users (ffD, dsp, ffDmux) and + // its ffD.D only has two (ffD, ffDmux) if (nusers(sigD) >= 3 && nusers(D) == 2) sigffDmuxY = sigD; sigD = std::move(D); @@ -276,7 +277,7 @@ match ffDmux filter GetSize(port(ffDmux, \Y)) >= GetSize(sigD) slice offset GetSize(port(ffDmux, \Y)) filter offset+GetSize(sigD) <= GetSize(port(ffDmux, \Y)) - filter port(ffDmux, \Y).extract(offset, GetSize(sigB)) == sigD + filter port(ffDmux, \Y).extract(offset, GetSize(sigD)) == sigD choice AB {\A, \B} filter offset+GetSize(sigffDmuxY) <= GetSize(port(ffDmux, \Y)) filter port(ffDmux, AB).extract(offset, GetSize(sigffDmuxY)) == sigffDmuxY @@ -290,17 +291,17 @@ match ffMmux if nusers(sigM) == 2 select ffMmux->type.in($mux) choice BA {\B, \A} - // new-value net must have exactly two users: dsp and ffM + // new-value net must have exactly two users: dsp and ffMmux select nusers(port(ffMmux, BA)) == 2 define AB (BA == \B ? \A : \B) // keep-last-value net must have at least three users: ffMmux, ffM, downstream sink(s) select nusers(port(ffMmux, AB)) >= 3 // ffMmux output must have two users: ffMmux and ffM.D select nusers(port(ffMmux, \Y)) == 2 - filter GetSize(port(ffMmux, \Y)) <= GetSize(sigM) - filter port(ffMmux, BA) == sigM.extract(0, GetSize(port(ffMmux, \Y))) + filter GetSize(unextend(port(ffMmux, BA))) <= GetSize(sigM) + filter unextend(port(ffMmux, BA)) == sigM.extract(0, GetSize(unextend(port(ffMmux, BA)))) // Remaining bits on sigM must not have any other users - filter nusers(sigM.extract_end(GetSize(port(ffMmux, BA)))) <= 1 + filter nusers(sigM.extract_end(GetSize(unextend(port(ffMmux, BA))))) <= 1 define pol (AB == \A) set ffMenpol pol optional @@ -367,9 +368,9 @@ match postAdd select nusers(port(postAdd, AB)) <= 3 filter ffMmux || nusers(port(postAdd, AB)) == 2 filter !ffMmux || nusers(port(postAdd, AB)) == 3 - filter GetSize(port(postAdd, AB)) <= GetSize(sigP) - filter port(postAdd, AB) == sigP.extract(0, GetSize(port(postAdd, AB))) - filter nusers(sigP.extract_end(GetSize(port(postAdd, AB)))) <= 1 + filter GetSize(unextend(port(postAdd, AB))) <= GetSize(sigP) + filter unextend(port(postAdd, AB)) == sigP.extract(0, GetSize(unextend(port(postAdd, AB)))) + filter nusers(sigP.extract_end(GetSize(unextend(port(postAdd, AB))))) <= 1 set postAddAB AB optional endmatch @@ -495,6 +496,56 @@ code sigC sigC = port(postAddMux, postAddMuxAB == \A ? \B : \A); endcode +match ffC + if param(dsp, \CREG).as_int() == 0 + select ffC->type.in($dff) + // DSP48E1 does not support clock inversion + select param(ffC, \CLK_POLARITY).as_bool() + filter GetSize(port(ffC, \Q)) >= GetSize(sigD) + slice offset GetSize(port(ffC, \Q)) + filter offset+GetSize(sigC) <= GetSize(port(ffC, \Q)) + filter port(ffC, \Q).extract(offset, GetSize(sigC)) == sigC + optional +endmatch + +code sigC sigffCmuxY clock + if (ffC) { + for (auto b : port(ffC, \Q)) + if (b.wire->get_bool_attribute(\keep)) + reject; + + SigBit c = port(ffC, \CLK).as_bit(); + if (clock != SigBit() && c != clock) + reject; + clock = c; + + SigSpec C = sigC; + C.replace(port(ffC, \Q), port(ffC, \D)); + // Only search for ffCmux if ffC.Q has at + // least 3 users (ffC, dsp, ffCmux) and + // its ffC.D only has two (ffC, ffCmux) + if (nusers(sigC) >= 3 && nusers(C) == 2) + sigffCmuxY = sigC; + sigC = std::move(C); + } +endcode + +match ffCmux + if !sigffCmuxY.empty() + select ffCmux->type.in($mux) + index port(ffCmux, \Y) === port(ffC, \D) + filter GetSize(port(ffCmux, \Y)) >= GetSize(sigC) + slice offset GetSize(port(ffCmux, \Y)) + filter offset+GetSize(sigC) <= GetSize(port(ffCmux, \Y)) + filter port(ffCmux, \Y).extract(offset, GetSize(sigC)) == sigC + choice AB {\A, \B} + filter offset+GetSize(sigffCmuxY) <= GetSize(port(ffCmux, \Y)) + filter port(ffCmux, AB).extract(offset, GetSize(sigffCmuxY)) == sigffCmuxY + define pol (AB == \A) + set ffCenpol pol + optional +endmatch + code accept; endcode -- cgit v1.2.3 From e2c2d784c8217e4bcf29fb6b156b6a8285036b80 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 22:48:23 -0700 Subject: Make one check $shift(x)? only; change testcase to be 8b --- passes/pmgen/peepopt_shiftmul.pmg | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/peepopt_shiftmul.pmg b/passes/pmgen/peepopt_shiftmul.pmg index d4748ae19..e1da52182 100644 --- a/passes/pmgen/peepopt_shiftmul.pmg +++ b/passes/pmgen/peepopt_shiftmul.pmg @@ -50,8 +50,9 @@ code if (GetSize(const_factor_cnst) > 20) reject; - if (GetSize(port(shift, \Y)) > const_factor) - reject; + if (shift->type.in($shift, $shiftx)) + if (GetSize(port(shift, \Y)) > const_factor) + reject; int factor_bits = ceil_log2(const_factor); SigSpec mul_din = port(mul, const_factor_port == \A ? \B : \A); -- cgit v1.2.3 From a82e8df7d37c02258d36223bb16833331dc8808e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Fri, 16 Aug 2019 03:14:03 +0000 Subject: techmap: Add support for extracting init values of ports --- passes/techmap/techmap.cc | 71 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 5ce1bf7d6..51a65aea6 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -424,6 +424,18 @@ struct TechmapWorker SigMap sigmap(module); + dict init_bits; + pool remove_init_bits; + + for (auto wire : module->wires()) { + if (wire->attributes.count("\\init")) { + Const value = wire->attributes.at("\\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]; + } + } + TopoSort> cells; std::map> cell_to_inbit; std::map> outbit_to_cell; @@ -661,6 +673,17 @@ struct TechmapWorker bit = RTLIL::SigBit(RTLIL::State::Sx); parameters[stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const(); } + if (tpl->avail_parameters.count(stringf("\\_TECHMAP_WIREINIT_%s_", RTLIL::id2cstr(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[stringf("\\_TECHMAP_WIREINIT_%s_", RTLIL::id2cstr(conn.first))] = value; + } } int unique_bit_id_counter = 0; @@ -861,12 +884,25 @@ struct TechmapWorker TechmapWires twd = techmap_find_special_wires(tpl); for (auto &it : twd) { - if (it.first != "_TECHMAP_FAIL_" && it.first.substr(0, 12) != "_TECHMAP_DO_" && it.first.substr(0, 14) != "_TECHMAP_DONE_") + if (it.first != "_TECHMAP_FAIL_" && (it.first.substr(0, 20) != "_TECHMAP_REMOVEINIT_" || it.first[it.first.size()-1] != '_') && it.first.substr(0, 12) != "_TECHMAP_DO_" && it.first.substr(0, 14) != "_TECHMAP_DONE_") log_error("Techmap yielded unknown config wire %s.\n", it.first.c_str()); if (techmap_do_cache[tpl]) for (auto &it2 : it.second) if (!it2.value.is_fully_const()) log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(it2.wire->name), log_signal(it2.value)); + if (it.first.substr(0, 20) == "_TECHMAP_REMOVEINIT_" && techmap_do_cache[tpl]) { + for (auto &it2 : it.second) { + auto val = it2.value.as_const(); + auto wirename = RTLIL::escape_id(it.first.substr(20, it.first.size() - 20 - 1)); + auto it = cell->connections().find(wirename); + if (it != cell->connections().end()) { + auto sig = sigmap(it->second); + for (int i = 0; i < sig.size(); i++) + if (val[i] == State::S1) + remove_init_bits.insert(sig[i]); + } + } + } techmap_wire_names.erase(it.first); } @@ -935,6 +971,25 @@ struct TechmapWorker handled_cells.insert(cell); } + if (!remove_init_bits.empty()) { + for (auto wire : module->wires()) + if (wire->attributes.count("\\init")) { + Const &value = wire->attributes.at("\\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("\\init"); + } + } + } + if (log_continue) { log_header(design, "Continuing TECHMAP pass.\n"); log_continue = false; @@ -1047,6 +1102,13 @@ struct TechmapPass : public Pass { log("\n"); log(" It is possible to combine both prefixes to 'RECURSION; CONSTMAP; '.\n"); log("\n"); + log(" _TECHMAP_REMOVEINIT__\n"); + log(" When this wire is set to a constant value, the init attribute of the wire(s)\n"); + log(" connected to this port will be consumed. This wire must have the same\n"); + log(" width as the given port, and for every bit that is set to 1 in the value,\n"); + log(" the corresponding init attribute bit will be changed to 1'bx. If all\n"); + log(" bits of an init attribute are left as x, it will be removed.\n"); + log("\n"); log("In addition to this special wires, techmap also supports special parameters in\n"); log("modules in the map file:\n"); log("\n"); @@ -1060,6 +1122,13 @@ struct TechmapPass : public Pass { log(" former has a 1-bit for each constant input bit and the latter has the\n"); log(" value for this bit. The unused bits of the latter are set to undef (x).\n"); log("\n"); + log(" _TECHMAP_WIREINIT__\n"); + log(" When a parameter with this name exists, it will be set to the initial\n"); + log(" value of the wire(s) connected to the given port, as specified by the init\n"); + log(" attribute. If the attribute doesn't exist, x will be filled for the\n"); + log(" missing bits. To remove the init attribute bits used, use the\n"); + log(" _TECHMAP_REMOVEINIT_*_ wires.\n"); + log("\n"); log(" _TECHMAP_BITS_CONNMAP_\n"); log(" _TECHMAP_CONNMAP__\n"); log(" For an N-bit port, the _TECHMAP_CONNMAP__ parameter, if it\n"); -- cgit v1.2.3 From 8d128ba6d079fd5f0741c31a9308bf06aaf4673c Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 9 Sep 2019 12:40:01 +0800 Subject: passes: opt_share: don't statically initialize mergeable_type_map In 3d3779b0376b8204ed7637053176a07b7271ac1d this got turned from a `std::map` to `std::map`. Consequently, this exposed some initialization sequencing issues (#1361). Only initialize the map when it's first used, to avoid these static issues. This fixes #1361. Signed-off-by: Sean Cross --- passes/opt/opt_share.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc index c53fb3113..2c456705c 100644 --- a/passes/opt/opt_share.cc +++ b/passes/opt/opt_share.cc @@ -108,12 +108,13 @@ bool cell_supported(RTLIL::Cell *cell) return false; } -std::map mergeable_type_map{ - {ID($sub), ID($add)}, -}; +std::map mergeable_type_map; bool mergeable(RTLIL::Cell *a, RTLIL::Cell *b) { + if (mergeable_type_map.empty()) { + mergeable_type_map.insert({ID($sub), ID($add)}); + } auto a_type = a->type; if (mergeable_type_map.count(a_type)) a_type = mergeable_type_map.at(a_type); -- cgit v1.2.3 From 04bc287271354d3a1770ae7a9f8f1de9341b9253 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 9 Sep 2019 15:51:14 -0700 Subject: Refactor using subpattern in_dffe --- passes/pmgen/xilinx_dsp.pmg | 386 +++++++++++++++++--------------------------- 1 file changed, 146 insertions(+), 240 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 6b981bc13..e611bfb3b 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -7,11 +7,21 @@ state postAddAB postAddMuxAB state ffAenpol ffADenpol ffBenpol ffCenpol ffDenpol ffMenpol ffPenpol state ffPoffset +state ffAD ffADmux ffA ffAmux ffB ffBmux ffC ffCmux ffD ffDmux + +// subpattern +state dffQ +state dffenpol_ +udata dffD +udata dffclock +udata dff dffmux +udata dffenpol + match dsp select dsp->type.in(\DSP48E1) endmatch -code unextend sigA sigffAmuxY sigB sigffBmuxY sigC sigffCmuxY sigD sigffDmuxY sigM +code unextend sigA sigB sigC sigD sigM unextend = [](const SigSpec &sig) { int i; for (i = GetSize(sig)-1; i > 0; i--) @@ -39,60 +49,24 @@ code unextend sigA sigffAmuxY sigB sigffBmuxY sigC sigffCmuxY sigD sigffDmuxY si log_assert(nusers(P.extract_end(i)) <= 1); //if (GetSize(sigM) <= 10) // reject; - - sigffAmuxY = SigSpec(); - sigffBmuxY = SigSpec(); - sigffCmuxY = SigSpec(); - sigffDmuxY = SigSpec(); endcode -match ffAD - if param(dsp, \ADREG).as_int() == 0 - select ffAD->type.in($dff) - // DSP48E1 does not support clock inversion - select param(ffAD, \CLK_POLARITY).as_bool() - filter GetSize(port(ffAD, \Q)) >= GetSize(sigA) - slice offset GetSize(port(ffAD, \Q)) - filter offset+GetSize(sigA) <= GetSize(port(ffAD, \Q)) - filter port(ffAD, \Q).extract(offset, GetSize(sigA)) == sigA - optional -endmatch - -code sigA sigffAmuxY clock - if (ffAD) { - for (auto b : port(ffAD, \Q)) - if (b.wire->get_bool_attribute(\keep)) - reject; - - clock = port(ffAD, \CLK).as_bit(); - - SigSpec A = sigA; - A.replace(port(ffAD, \Q), port(ffAD, \D)); - // Only search for ffAmux if ffA.Q has at - // least 3 users (ffA, dsp, ffAmux) and - // its ffA.D only has two (ffA, ffAmux) - if (nusers(sigA) >= 3 && nusers(A) == 2) - sigffAmuxY = sigA; - sigA = std::move(A); +code dffQ ffAD ffADmux ffADenpol sigA clock + if (param(dsp, \ADREG).as_int() == 0) { + dffQ = sigA; + subpattern(in_dffe); + if (dff) { + ffAD = dff; + clock = dffclock; + if (dffmux) { + ffADmux = dffmux; + ffADenpol = dffenpol; + } + sigA = dffD; + } } endcode -match ffADmux - if !sigffAmuxY.empty() - select ffADmux->type.in($mux) - index port(ffADmux, \Y) === port(ffAD, \D) - filter GetSize(port(ffADmux, \Y)) >= GetSize(sigA) - slice offset GetSize(port(ffADmux, \Y)) - filter offset+GetSize(sigA) <= GetSize(port(ffADmux, \Y)) - filter port(ffADmux, \Y).extract(offset, GetSize(sigA)) == sigA - choice AB {\A, \B} - filter offset+GetSize(sigffAmuxY) <= GetSize(port(ffADmux, \Y)) - filter port(ffADmux, AB).extract(offset, GetSize(sigffAmuxY)) == sigffAmuxY - define pol (AB == \A) - set ffADenpol pol - optional -endmatch - match preAdd if sigD.empty() || sigD.is_fully_zero() // Ensure that preAdder not already used @@ -123,169 +97,66 @@ code sigA sigD } endcode -match ffA - if !preAdd - if param(dsp, \AREG).as_int() == 0 - select ffA->type.in($dff) - // DSP48E1 does not support clock inversion - select param(ffA, \CLK_POLARITY).as_bool() - filter GetSize(port(ffA, \Q)) >= GetSize(sigA) - slice offset GetSize(port(ffA, \Q)) - filter offset+GetSize(sigA) <= GetSize(port(ffA, \Q)) - filter port(ffA, \Q).extract(offset, GetSize(sigA)) == sigA - optional -endmatch - -code sigA sigffAmuxY clock - if (ffA) { - for (auto b : port(ffA, \Q)) - if (b.wire->get_bool_attribute(\keep)) - reject; - - clock = port(ffA, \CLK).as_bit(); - - SigSpec A = sigA; - A.replace(port(ffA, \Q), port(ffA, \D)); - // Only search for ffAmux if ffA.Q has at - // least 3 users (ffA, dsp, ffAmux) and - // its ffA.D only has two (ffA, ffAmux) - if (nusers(sigA) >= 3 && nusers(A) == 2) - sigffAmuxY = sigA; - sigA = std::move(A); - } - else if (!preAdd) { - sigffAmuxY = SigSpec(); +code dffQ ffA ffAmux ffAenpol sigA clock ffAD ffADmux ffADenpol + // Only search for ffA if there was a pre-adder + // (otherwise ffA would have been matched as ffAD) + if (preAdd) { + if (param(dsp, \AREG).as_int() == 0) { + dffQ = sigA; + subpattern(in_dffe); + if (dff) { + ffA = dff; + clock = dffclock; + if (dffmux) { + ffAmux = dffmux; + ffAenpol = dffenpol; + } + sigA = dffD; + } + } } -endcode - -match ffAmux - if !sigffAmuxY.empty() - select ffAmux->type.in($mux) - index port(ffAmux, \Y) === port(ffA, \D) - filter GetSize(port(ffAmux, \Y)) >= GetSize(sigA) - slice offset GetSize(port(ffAmux, \Y)) - filter offset+GetSize(sigA) <= GetSize(port(ffAmux, \Y)) - filter port(ffAmux, \Y).extract(offset, GetSize(sigA)) == sigA - choice AB {\A, \B} - filter offset+GetSize(sigffAmuxY) <= GetSize(port(ffAmux, \Y)) - filter port(ffAmux, AB).extract(offset, GetSize(sigffAmuxY)) == sigffAmuxY - define pol (AB == \A) - set ffAenpol pol - optional -endmatch - -code ffA ffAmux ffAenpol ffAD ffADmux - // Move AD register to A if no pre-adder - if (!ffA && !preAdd && ffAD) { - ffA = ffAD; - ffAmux = ffADmux; + // And if there wasn't a pre-adder, + // move AD register to A + else if (ffAD) { + log_assert(!ffA && !ffAmux); + std::swap(ffA, ffAD); + std::swap(ffAmux, ffADmux); ffAenpol = ffADenpol; - - ffAD = nullptr; - ffADmux = nullptr; } endcode -match ffB - if param(dsp, \BREG).as_int() == 0 - select ffB->type.in($dff) - // DSP48E1 does not support clock inversion - select param(ffB, \CLK_POLARITY).as_bool() - filter GetSize(port(ffB, \Q)) >= GetSize(sigB) - slice offset GetSize(port(ffB, \Q)) - filter offset+GetSize(sigB) <= GetSize(port(ffB, \Q)) - filter port(ffB, \Q).extract(offset, GetSize(sigB)) == sigB - optional -endmatch - -code sigB sigffBmuxY clock - if (ffB) { - for (auto b : port(ffB, \Q)) - if (b.wire->get_bool_attribute(\keep)) - reject; - - SigBit c = port(ffB, \CLK).as_bit(); - if (clock != SigBit() && c != clock) - reject; - clock = c; - - SigSpec B = sigB; - B.replace(port(ffB, \Q), port(ffB, \D)); - // Only search for ffBmux if ffB.Q has at - // least 3 users (ffB, dsp, ffBmux) and - // its ffB.D only has two (ffB, ffBmux) - if (nusers(sigB) >= 3 && nusers(B) == 2) - sigffBmuxY = sigB; - sigB = std::move(B); +code dffQ ffB ffBmux ffBenpol sigB clock + if (param(dsp, \BREG).as_int() == 0) { + dffQ = sigB; + subpattern(in_dffe); + if (dff) { + ffB = dff; + clock = dffclock; + if (dffmux) { + ffBmux = dffmux; + ffBenpol = dffenpol; + } + sigB = dffD; + } } endcode -match ffBmux - if !sigffBmuxY.empty() - select ffBmux->type.in($mux) - index port(ffBmux, \Y) === port(ffB, \D) - filter GetSize(port(ffBmux, \Y)) >= GetSize(sigB) - slice offset GetSize(port(ffBmux, \Y)) - filter offset+GetSize(sigB) <= GetSize(port(ffBmux, \Y)) - filter port(ffBmux, \Y).extract(offset, GetSize(sigB)) == sigB - choice AB {\A, \B} - filter offset+GetSize(sigffBmuxY) <= GetSize(port(ffBmux, \Y)) - filter port(ffBmux, AB).extract(offset, GetSize(sigffBmuxY)) == sigffBmuxY - define pol (AB == \A) - set ffBenpol pol - optional -endmatch - -match ffD - if param(dsp, \DREG).as_int() == 0 - select ffD->type.in($dff) - // DSP48E1 does not support clock inversion - select param(ffD, \CLK_POLARITY).as_bool() - filter GetSize(port(ffD, \Q)) >= GetSize(sigD) - slice offset GetSize(port(ffD, \Q)) - filter offset+GetSize(sigD) <= GetSize(port(ffD, \Q)) - filter port(ffD, \Q).extract(offset, GetSize(sigD)) == sigD - optional -endmatch - -code sigD sigffDmuxY clock - if (ffD) { - for (auto b : port(ffD, \Q)) - if (b.wire->get_bool_attribute(\keep)) - reject; - - SigBit c = port(ffD, \CLK).as_bit(); - if (clock != SigBit() && c != clock) - reject; - clock = c; - - SigSpec D = sigD; - D.replace(port(ffD, \Q), port(ffD, \D)); - // Only search for ffDmux if ffD.Q has at - // least 3 users (ffD, dsp, ffDmux) and - // its ffD.D only has two (ffD, ffDmux) - if (nusers(sigD) >= 3 && nusers(D) == 2) - sigffDmuxY = sigD; - sigD = std::move(D); +code dffQ ffD ffDmux ffDenpol sigD clock + if (param(dsp, \DREG).as_int() == 0) { + dffQ = sigD; + subpattern(in_dffe); + if (dff) { + ffD = dff; + clock = dffclock; + if (dffmux) { + ffDmux = dffmux; + ffDenpol = dffenpol; + } + sigD = dffD; + } } endcode -match ffDmux - if !sigffDmuxY.empty() - select ffDmux->type.in($mux) - index port(ffDmux, \Y) === port(ffD, \D) - filter GetSize(port(ffDmux, \Y)) >= GetSize(sigD) - slice offset GetSize(port(ffDmux, \Y)) - filter offset+GetSize(sigD) <= GetSize(port(ffDmux, \Y)) - filter port(ffDmux, \Y).extract(offset, GetSize(sigD)) == sigD - choice AB {\A, \B} - filter offset+GetSize(sigffDmuxY) <= GetSize(port(ffDmux, \Y)) - filter port(ffDmux, AB).extract(offset, GetSize(sigffDmuxY)) == sigffDmuxY - define pol (AB == \A) - set ffDenpol pol - optional -endmatch - match ffMmux if param(dsp, \MREG).as_int() == 0 if nusers(sigM) == 2 @@ -496,56 +367,91 @@ code sigC sigC = port(postAddMux, postAddMuxAB == \A ? \B : \A); endcode -match ffC - if param(dsp, \CREG).as_int() == 0 - select ffC->type.in($dff) +code dffQ ffC ffCmux ffCenpol sigC clock + if (param(dsp, \CREG).as_int() == 0) { + dffQ = sigC; + subpattern(in_dffe); + if (dff) { + ffC = dff; + clock = dffclock; + if (dffmux) { + ffCmux = dffmux; + ffCenpol = dffenpol; + } + sigC = dffD; + } + } +endcode + +code + accept; +endcode + +subpattern in_dffe +arg dffQ clock dffenpol_ + +code + dff = nullptr; + dffmux = nullptr; +endcode + +match ff + select ff->type.in($dff) // DSP48E1 does not support clock inversion - select param(ffC, \CLK_POLARITY).as_bool() - filter GetSize(port(ffC, \Q)) >= GetSize(sigD) - slice offset GetSize(port(ffC, \Q)) - filter offset+GetSize(sigC) <= GetSize(port(ffC, \Q)) - filter port(ffC, \Q).extract(offset, GetSize(sigC)) == sigC - optional + select param(ff, \CLK_POLARITY).as_bool() + filter GetSize(port(ff, \Q)) >= GetSize(dffQ) + slice offset GetSize(port(ff, \Q)) + filter offset+GetSize(dffQ) <= GetSize(port(ff, \Q)) + filter port(ff, \Q).extract(offset, GetSize(dffQ)) == dffQ + semioptional endmatch -code sigC sigffCmuxY clock - if (ffC) { - for (auto b : port(ffC, \Q)) +code dffQ + if (ff) { + for (auto b : dffQ) if (b.wire->get_bool_attribute(\keep)) reject; - SigBit c = port(ffC, \CLK).as_bit(); - if (clock != SigBit() && c != clock) - reject; - clock = c; - - SigSpec C = sigC; - C.replace(port(ffC, \Q), port(ffC, \D)); - // Only search for ffCmux if ffC.Q has at - // least 3 users (ffC, dsp, ffCmux) and - // its ffC.D only has two (ffC, ffCmux) - if (nusers(sigC) >= 3 && nusers(C) == 2) - sigffCmuxY = sigC; - sigC = std::move(C); + if (clock != SigBit()) { + if (port(ff, \CLK) != clock) + reject; + } + else + dffclock = port(ff, \CLK); + + dff = ff; + dffD = dffQ; + dffD.replace(port(ff, \Q), port(ff, \D)); + // Only search for ffmux if ff.Q has at + // least 3 users (ff, dsp, ffmux) and + // its ff.D only has two (ff, ffmux) + if (!(nusers(dffQ) >= 3 && nusers(dffD) == 2)) + dffQ = SigSpec(); } + else + dffQ = SigSpec(); endcode -match ffCmux - if !sigffCmuxY.empty() - select ffCmux->type.in($mux) - index port(ffCmux, \Y) === port(ffC, \D) - filter GetSize(port(ffCmux, \Y)) >= GetSize(sigC) - slice offset GetSize(port(ffCmux, \Y)) - filter offset+GetSize(sigC) <= GetSize(port(ffCmux, \Y)) - filter port(ffCmux, \Y).extract(offset, GetSize(sigC)) == sigC +match ffmux + if !dffQ.empty() + select ffmux->type.in($mux) + index port(ffmux, \Y) === port(ff, \D) + filter GetSize(port(ffmux, \Y)) >= GetSize(dffD) + slice offset GetSize(port(ffmux, \Y)) + filter offset+GetSize(dffD) <= GetSize(port(ffmux, \Y)) + filter port(ffmux, \Y).extract(offset, GetSize(dffD)) == dffD choice AB {\A, \B} - filter offset+GetSize(sigffCmuxY) <= GetSize(port(ffCmux, \Y)) - filter port(ffCmux, AB).extract(offset, GetSize(sigffCmuxY)) == sigffCmuxY + filter offset+GetSize(dffQ) <= GetSize(port(ffmux, \Y)) + filter port(ffmux, AB).extract(offset, GetSize(dffQ)) == dffQ define pol (AB == \A) - set ffCenpol pol - optional + set dffenpol_ pol + semioptional endmatch code - accept; + if (ffmux) { + dffmux = ffmux; + dffenpol = dffenpol_; + dffD = port(ffmux, dffenpol ? \B : \A); + } endcode -- cgit v1.2.3 From 5f8f0e13833ef052adb4d2d3deb8e965734127fd Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 9 Sep 2019 15:59:10 -0700 Subject: Tidy up --- passes/pmgen/xilinx_dsp.pmg | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index e611bfb3b..afbd6ef81 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -390,11 +390,6 @@ endcode subpattern in_dffe arg dffQ clock dffenpol_ -code - dff = nullptr; - dffmux = nullptr; -endcode - match ff select ff->type.in($dff) // DSP48E1 does not support clock inversion @@ -428,8 +423,10 @@ code dffQ if (!(nusers(dffQ) >= 3 && nusers(dffD) == 2)) dffQ = SigSpec(); } - else + else { + dff = nullptr; dffQ = SigSpec(); + } endcode match ffmux @@ -454,4 +451,6 @@ code dffenpol = dffenpol_; dffD = port(ffmux, dffenpol ? \B : \A); } + else + dffmux = nullptr; endcode -- cgit v1.2.3 From 1df9c5d277aa70d4dc1088d0030a756f342bb8fb Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 9 Sep 2019 16:07:40 -0700 Subject: Oops --- passes/pmgen/xilinx_dsp.pmg | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index afbd6ef81..f01eeb245 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -411,8 +411,7 @@ code dffQ if (port(ff, \CLK) != clock) reject; } - else - dffclock = port(ff, \CLK); + dffclock = port(ff, \CLK); dff = ff; dffD = dffQ; -- cgit v1.2.3 From 6348f9512c5dd9de9529a5e6cac58ad46a742309 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 9 Sep 2019 16:45:38 -0700 Subject: Rename --- passes/pmgen/xilinx_dsp.pmg | 54 ++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index f01eeb245..3185c4641 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -10,8 +10,8 @@ state ffPoffset state ffAD ffADmux ffA ffAmux ffB ffBmux ffC ffCmux ffD ffDmux // subpattern -state dffQ -state dffenpol_ +state argQ +state ffenpol udata dffD udata dffclock udata dff dffmux @@ -51,9 +51,9 @@ code unextend sigA sigB sigC sigD sigM // reject; endcode -code dffQ ffAD ffADmux ffADenpol sigA clock +code argQ ffAD ffADmux ffADenpol sigA clock if (param(dsp, \ADREG).as_int() == 0) { - dffQ = sigA; + argQ = sigA; subpattern(in_dffe); if (dff) { ffAD = dff; @@ -97,12 +97,12 @@ code sigA sigD } endcode -code dffQ ffA ffAmux ffAenpol sigA clock ffAD ffADmux ffADenpol +code argQ ffA ffAmux ffAenpol sigA clock ffAD ffADmux ffADenpol // Only search for ffA if there was a pre-adder // (otherwise ffA would have been matched as ffAD) if (preAdd) { if (param(dsp, \AREG).as_int() == 0) { - dffQ = sigA; + argQ = sigA; subpattern(in_dffe); if (dff) { ffA = dff; @@ -125,9 +125,9 @@ code dffQ ffA ffAmux ffAenpol sigA clock ffAD ffADmux ffADenpol } endcode -code dffQ ffB ffBmux ffBenpol sigB clock +code argQ ffB ffBmux ffBenpol sigB clock if (param(dsp, \BREG).as_int() == 0) { - dffQ = sigB; + argQ = sigB; subpattern(in_dffe); if (dff) { ffB = dff; @@ -141,9 +141,9 @@ code dffQ ffB ffBmux ffBenpol sigB clock } endcode -code dffQ ffD ffDmux ffDenpol sigD clock +code argQ ffD ffDmux ffDenpol sigD clock if (param(dsp, \DREG).as_int() == 0) { - dffQ = sigD; + argQ = sigD; subpattern(in_dffe); if (dff) { ffD = dff; @@ -367,9 +367,9 @@ code sigC sigC = port(postAddMux, postAddMuxAB == \A ? \B : \A); endcode -code dffQ ffC ffCmux ffCenpol sigC clock +code argQ ffC ffCmux ffCenpol sigC clock if (param(dsp, \CREG).as_int() == 0) { - dffQ = sigC; + argQ = sigC; subpattern(in_dffe); if (dff) { ffC = dff; @@ -388,22 +388,22 @@ code endcode subpattern in_dffe -arg dffQ clock dffenpol_ +arg argQ clock ffenpol match ff select ff->type.in($dff) // DSP48E1 does not support clock inversion select param(ff, \CLK_POLARITY).as_bool() - filter GetSize(port(ff, \Q)) >= GetSize(dffQ) + filter GetSize(port(ff, \Q)) >= GetSize(argQ) slice offset GetSize(port(ff, \Q)) - filter offset+GetSize(dffQ) <= GetSize(port(ff, \Q)) - filter port(ff, \Q).extract(offset, GetSize(dffQ)) == dffQ + filter offset+GetSize(argQ) <= GetSize(port(ff, \Q)) + filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ semioptional endmatch -code dffQ +code argQ if (ff) { - for (auto b : dffQ) + for (auto b : argQ) if (b.wire->get_bool_attribute(\keep)) reject; @@ -414,22 +414,22 @@ code dffQ dffclock = port(ff, \CLK); dff = ff; - dffD = dffQ; + dffD = argQ; dffD.replace(port(ff, \Q), port(ff, \D)); // Only search for ffmux if ff.Q has at // least 3 users (ff, dsp, ffmux) and // its ff.D only has two (ff, ffmux) - if (!(nusers(dffQ) >= 3 && nusers(dffD) == 2)) - dffQ = SigSpec(); + if (!(nusers(argQ) >= 3 && nusers(dffD) == 2)) + argQ = SigSpec(); } else { dff = nullptr; - dffQ = SigSpec(); + argQ = SigSpec(); } endcode match ffmux - if !dffQ.empty() + if !argQ.empty() select ffmux->type.in($mux) index port(ffmux, \Y) === port(ff, \D) filter GetSize(port(ffmux, \Y)) >= GetSize(dffD) @@ -437,17 +437,17 @@ match ffmux filter offset+GetSize(dffD) <= GetSize(port(ffmux, \Y)) filter port(ffmux, \Y).extract(offset, GetSize(dffD)) == dffD choice AB {\A, \B} - filter offset+GetSize(dffQ) <= GetSize(port(ffmux, \Y)) - filter port(ffmux, AB).extract(offset, GetSize(dffQ)) == dffQ + filter offset+GetSize(argQ) <= GetSize(port(ffmux, \Y)) + filter port(ffmux, AB).extract(offset, GetSize(argQ)) == argQ define pol (AB == \A) - set dffenpol_ pol + set ffenpol pol semioptional endmatch code if (ffmux) { dffmux = ffmux; - dffenpol = dffenpol_; + dffenpol = ffenpol; dffD = port(ffmux, dffenpol ? \B : \A); } else -- cgit v1.2.3 From be0eaf3a9abd410d9ea2962a186b104d8ed0cc04 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 9 Sep 2019 16:46:33 -0700 Subject: Fix misspelling --- passes/pmgen/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/README.md b/passes/pmgen/README.md index 0856c9ba3..2f5b8d0b2 100644 --- a/passes/pmgen/README.md +++ b/passes/pmgen/README.md @@ -352,7 +352,7 @@ state variables used to pass arguments. subpattern tail ... -Subpatterns cann be called recursively. +Subpatterns can be called recursively. If a `subpattern` statement is preceded by a `fallthrough` statement, this is equivalent to calling the subpattern at the end of the preceding block. -- cgit v1.2.3 From 2c044304453ed0f2533af30cfbb347bf0fe6354d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 9 Sep 2019 20:57:03 -0700 Subject: Only trim sigM if USE_MULT; only look for ffM then too --- passes/pmgen/xilinx_dsp.pmg | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 3185c4641..07432dfc7 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -39,16 +39,18 @@ code unextend sigA sigB sigC sigD sigM sigD = dsp->connections_.at(\D, SigSpec()); SigSpec P = port(dsp, \P); - // Only care about those bits that are used - int i; - for (i = 0; i < GetSize(P); i++) { - if (nusers(P[i]) <= 1) - break; - sigM.append(P[i]); + if (dsp->parameters.at(\USE_MULT, Const("MULTIPLY")).decode_string() == "MULTIPLY") { + // Only care about those bits that are used + int i; + for (i = 0; i < GetSize(P); i++) { + if (nusers(P[i]) <= 1) + break; + sigM.append(P[i]); + } + log_assert(nusers(P.extract_end(i)) <= 1); } - log_assert(nusers(P.extract_end(i)) <= 1); - //if (GetSize(sigM) <= 10) - // reject; + else + sigM = P; endcode code argQ ffAD ffADmux ffADenpol sigA clock @@ -159,6 +161,7 @@ endcode match ffMmux if param(dsp, \MREG).as_int() == 0 + if dsp->parameters.at(\USE_MULT, Const("MULTIPLY")).decode_string() == "MULTIPLY" if nusers(sigM) == 2 select ffMmux->type.in($mux) choice BA {\B, \A} @@ -194,6 +197,7 @@ match ffM_enable endmatch match ffM + if dsp->parameters.at(\USE_MULT, Const("MULTIPLY")).decode_string() == "MULTIPLY" if !ffM_enable if param(dsp, \MREG).as_int() == 0 if nusers(sigM) == 2 -- cgit v1.2.3 From 5a6552e56bf278a4cb5249303680e10f3e1a79b1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 9 Sep 2019 20:57:20 -0700 Subject: Add initial USE_SIMD=FOUR12 support --- passes/pmgen/xilinx_dsp.cc | 157 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 10308de57..2ab0cfa71 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -25,6 +25,161 @@ PRIVATE_NAMESPACE_BEGIN #include "passes/pmgen/xilinx_dsp_pm.h" +void pack_xilinx_simd(Module *module, const std::vector &selected_cells) +{ + std::deque simd12, simd24; + + for (auto cell : selected_cells) { + if (!cell->type.in("$add")) + continue; + SigSpec Y = cell->getPort("\\Y"); + if (!Y.is_chunk()) + continue; + if (!Y.as_chunk().wire->get_strpool_attribute("\\use_dsp").count("simd")) + continue; + if (GetSize(Y) > 25) + continue; + SigSpec A = cell->getPort("\\A"); + SigSpec B = cell->getPort("\\B"); + if (GetSize(Y) <= 13) { + if (GetSize(A) > 12) + continue; + if (GetSize(B) > 12) + continue; + simd12.push_back(cell); + } + else { + if (GetSize(A) > 24) + continue; + if (GetSize(B) > 24) + continue; + simd24.push_back(cell); + } + } + + auto addDsp = [module] { + Cell *cell = module->addCell(NEW_ID, "\\DSP48E1"); + cell->setParam("\\ACASCREG", 0); + cell->setParam("\\ADREG", 0); + cell->setParam("\\A_INPUT", Const("DIRECT")); + cell->setParam("\\ALUMODEREG", 0); + cell->setParam("\\AREG", 0); + cell->setParam("\\BCASCREG", 0); + cell->setParam("\\B_INPUT", Const("DIRECT")); + cell->setParam("\\BREG", 0); + cell->setParam("\\CARRYINREG", 0); + cell->setParam("\\CARRYINSELREG", 0); + cell->setParam("\\CREG", 0); + cell->setParam("\\DREG", 0); + cell->setParam("\\INMODEREG", 0); + cell->setParam("\\MREG", 0); + cell->setParam("\\OPMODEREG", 0); + cell->setParam("\\PREG", 0); + cell->setParam("\\USE_MULT", Const("NONE")); + + cell->setPort("\\D", Const(0, 24)); + cell->setPort("\\INMODE", Const(0, 5)); + cell->setPort("\\ALUMODE", Const(0, 4)); + cell->setPort("\\OPMODE", Const(0, 7)); + cell->setPort("\\CARRYINSEL", Const(0, 3)); + cell->setPort("\\ACIN", Const(0, 30)); + cell->setPort("\\BCIN", Const(0, 18)); + cell->setPort("\\PCIN", Const(0, 48)); + cell->setPort("\\CARRYIN", Const(0, 1)); + return cell; + }; + + SigSpec AB; + SigSpec C; + SigSpec P; + SigSpec CARRYOUT; + auto f12 = [&AB,&C,&P,&CARRYOUT,module](Cell *lane) { + SigSpec A = lane->getPort("\\A"); + SigSpec B = lane->getPort("\\B"); + SigSpec Y = lane->getPort("\\Y"); + A.extend_u0(12, lane->getParam("\\A_SIGNED").as_bool()); + B.extend_u0(12, lane->getParam("\\B_SIGNED").as_bool()); + AB.append(A); + C.append(B); + if (GetSize(Y) < 13) + Y.append(module->addWire(NEW_ID, 13-GetSize(Y))); + else + log_assert(GetSize(Y) == 13); + P.append(Y.extract(0, 12)); + CARRYOUT.append(Y[12]); + }; + while (simd12.size() > 1) { + AB = SigSpec(); + C = SigSpec(); + P = SigSpec(); + CARRYOUT = SigSpec(); + + Cell *lane1 = simd12.front(); + simd12.pop_front(); + Cell *lane2 = simd12.front(); + simd12.pop_front(); + Cell *lane3 = nullptr; + Cell *lane4 = nullptr; + + if (!simd12.empty()) { + lane3 = simd12.front(); + simd12.pop_front(); + if (!simd12.empty()) { + lane4 = simd12.front(); + simd12.pop_front(); + } + } + + log("Analysing %s.%s for Xilinx DSP SIMD12 packing.\n", log_id(module), log_id(lane1)); + + Cell *cell = addDsp(); + cell->setParam("\\USE_SIMD", Const("FOUR12")); + // X = A:B + // Y = 0 + // Z = C + cell->setPort("\\OPMODE", Const::from_string("0110011")); + + log_assert(lane1); + log_assert(lane2); + f12(lane1); + f12(lane2); + if (lane3) { + f12(lane3); + if (lane4) + f12(lane4); + else { + AB.append(Const(0, 12)); + C.append(Const(0, 12)); + P.append(module->addWire(NEW_ID, 12)); + CARRYOUT.append(module->addWire(NEW_ID, 1)); + } + } + else { + AB.append(Const(0, 24)); + C.append(Const(0, 24)); + P.append(module->addWire(NEW_ID, 24)); + CARRYOUT.append(module->addWire(NEW_ID, 2)); + } + log_assert(GetSize(AB) == 48); + log_assert(GetSize(C) == 48); + log_assert(GetSize(P) == 48); + log_assert(GetSize(CARRYOUT) == 4); + cell->setPort("\\A", AB.extract(18, 30)); + cell->setPort("\\B", AB.extract(0, 18)); + cell->setPort("\\C", C); + cell->setPort("\\P", P); + cell->setPort("\\CARRYOUT", CARRYOUT); + + module->remove(lane1); + module->remove(lane2); + if (lane3) module->remove(lane3); + if (lane4) module->remove(lane4); + + module->design->select(module, cell); + } +} + + void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) { auto &st = pm.st_xilinx_dsp; @@ -281,6 +436,8 @@ struct XilinxDspPass : public Pass { extra_args(args, argidx, design); for (auto module : design->selected_modules()) { + pack_xilinx_simd(module, module->selected_cells()); + xilinx_dsp_pm pm(module, module->selected_cells()); dict bit_to_driver; auto f = [&bit_to_driver](xilinx_dsp_pm &pm){ pack_xilinx_dsp(bit_to_driver, pm); }; -- cgit v1.2.3 From 0bb6fd8448aee02b7006dd1067cc556a85c6c266 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 9 Sep 2019 20:58:54 -0700 Subject: Refactor --- passes/pmgen/xilinx_dsp.cc | 66 +++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 33 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 2ab0cfa71..97cadd3c9 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -25,6 +25,38 @@ PRIVATE_NAMESPACE_BEGIN #include "passes/pmgen/xilinx_dsp_pm.h" +static Cell* addDsp(Module *module) { + Cell *cell = module->addCell(NEW_ID, "\\DSP48E1"); + cell->setParam("\\ACASCREG", 0); + cell->setParam("\\ADREG", 0); + cell->setParam("\\A_INPUT", Const("DIRECT")); + cell->setParam("\\ALUMODEREG", 0); + cell->setParam("\\AREG", 0); + cell->setParam("\\BCASCREG", 0); + cell->setParam("\\B_INPUT", Const("DIRECT")); + cell->setParam("\\BREG", 0); + cell->setParam("\\CARRYINREG", 0); + cell->setParam("\\CARRYINSELREG", 0); + cell->setParam("\\CREG", 0); + cell->setParam("\\DREG", 0); + cell->setParam("\\INMODEREG", 0); + cell->setParam("\\MREG", 0); + cell->setParam("\\OPMODEREG", 0); + cell->setParam("\\PREG", 0); + cell->setParam("\\USE_MULT", Const("NONE")); + + cell->setPort("\\D", Const(0, 24)); + cell->setPort("\\INMODE", Const(0, 5)); + cell->setPort("\\ALUMODE", Const(0, 4)); + cell->setPort("\\OPMODE", Const(0, 7)); + cell->setPort("\\CARRYINSEL", Const(0, 3)); + cell->setPort("\\ACIN", Const(0, 30)); + cell->setPort("\\BCIN", Const(0, 18)); + cell->setPort("\\PCIN", Const(0, 48)); + cell->setPort("\\CARRYIN", Const(0, 1)); + return cell; +} + void pack_xilinx_simd(Module *module, const std::vector &selected_cells) { std::deque simd12, simd24; @@ -57,38 +89,6 @@ void pack_xilinx_simd(Module *module, const std::vector &selected_cells) } } - auto addDsp = [module] { - Cell *cell = module->addCell(NEW_ID, "\\DSP48E1"); - cell->setParam("\\ACASCREG", 0); - cell->setParam("\\ADREG", 0); - cell->setParam("\\A_INPUT", Const("DIRECT")); - cell->setParam("\\ALUMODEREG", 0); - cell->setParam("\\AREG", 0); - cell->setParam("\\BCASCREG", 0); - cell->setParam("\\B_INPUT", Const("DIRECT")); - cell->setParam("\\BREG", 0); - cell->setParam("\\CARRYINREG", 0); - cell->setParam("\\CARRYINSELREG", 0); - cell->setParam("\\CREG", 0); - cell->setParam("\\DREG", 0); - cell->setParam("\\INMODEREG", 0); - cell->setParam("\\MREG", 0); - cell->setParam("\\OPMODEREG", 0); - cell->setParam("\\PREG", 0); - cell->setParam("\\USE_MULT", Const("NONE")); - - cell->setPort("\\D", Const(0, 24)); - cell->setPort("\\INMODE", Const(0, 5)); - cell->setPort("\\ALUMODE", Const(0, 4)); - cell->setPort("\\OPMODE", Const(0, 7)); - cell->setPort("\\CARRYINSEL", Const(0, 3)); - cell->setPort("\\ACIN", Const(0, 30)); - cell->setPort("\\BCIN", Const(0, 18)); - cell->setPort("\\PCIN", Const(0, 48)); - cell->setPort("\\CARRYIN", Const(0, 1)); - return cell; - }; - SigSpec AB; SigSpec C; SigSpec P; @@ -132,7 +132,7 @@ void pack_xilinx_simd(Module *module, const std::vector &selected_cells) log("Analysing %s.%s for Xilinx DSP SIMD12 packing.\n", log_id(module), log_id(lane1)); - Cell *cell = addDsp(); + Cell *cell = addDsp(module); cell->setParam("\\USE_SIMD", Const("FOUR12")); // X = A:B // Y = 0 -- cgit v1.2.3 From 31e60353acfae3335793c9640ab3fb131040512d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 9 Sep 2019 21:11:41 -0700 Subject: Support TWO24 --- passes/pmgen/xilinx_dsp.cc | 60 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 97cadd3c9..23f342a2b 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -80,13 +80,15 @@ void pack_xilinx_simd(Module *module, const std::vector &selected_cells) continue; simd12.push_back(cell); } - else { + else if (GetSize(Y) <= 25) { if (GetSize(A) > 24) continue; if (GetSize(B) > 24) continue; simd24.push_back(cell); } + else + log_abort(); } SigSpec AB; @@ -177,6 +179,62 @@ void pack_xilinx_simd(Module *module, const std::vector &selected_cells) module->design->select(module, cell); } + + auto f24 = [&AB,&C,&P,&CARRYOUT,module](Cell *lane) { + SigSpec A = lane->getPort("\\A"); + SigSpec B = lane->getPort("\\B"); + SigSpec Y = lane->getPort("\\Y"); + A.extend_u0(24, lane->getParam("\\A_SIGNED").as_bool()); + B.extend_u0(24, lane->getParam("\\B_SIGNED").as_bool()); + AB.append(A); + C.append(B); + if (GetSize(Y) < 25) + Y.append(module->addWire(NEW_ID, 25-GetSize(Y))); + else + log_assert(GetSize(Y) == 25); + P.append(Y.extract(0, 24)); + CARRYOUT.append(module->addWire(NEW_ID)); // TWO24 uses every other bit + CARRYOUT.append(Y[24]); + }; + while (simd24.size() > 1) { + AB = SigSpec(); + C = SigSpec(); + P = SigSpec(); + CARRYOUT = SigSpec(); + + Cell *lane1 = simd24.front(); + simd24.pop_front(); + Cell *lane2 = simd24.front(); + simd24.pop_front(); + + log("Analysing %s.%s for Xilinx DSP SIMD24 packing.\n", log_id(module), log_id(lane1)); + + Cell *cell = addDsp(module); + cell->setParam("\\USE_SIMD", Const("TWO24")); + // X = A:B + // Y = 0 + // Z = C + cell->setPort("\\OPMODE", Const::from_string("0110011")); + + log_assert(lane1); + log_assert(lane2); + f24(lane1); + f24(lane2); + log_assert(GetSize(AB) == 48); + log_assert(GetSize(C) == 48); + log_assert(GetSize(P) == 48); + log_assert(GetSize(CARRYOUT) == 4); + cell->setPort("\\A", AB.extract(18, 30)); + cell->setPort("\\B", AB.extract(0, 18)); + cell->setPort("\\C", C); + cell->setPort("\\P", P); + cell->setPort("\\CARRYOUT", CARRYOUT); + + module->remove(lane1); + module->remove(lane2); + + module->design->select(module, cell); + } } -- cgit v1.2.3 From 02cf9933b9e5c0bff360db13c3577c0a75cdb5b9 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 9 Sep 2019 21:39:42 -0700 Subject: Support subtraction as well --- passes/pmgen/xilinx_dsp.cc | 235 ++++++++++++++++++++++++--------------------- 1 file changed, 123 insertions(+), 112 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 23f342a2b..7bac1b974 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -59,10 +59,11 @@ static Cell* addDsp(Module *module) { void pack_xilinx_simd(Module *module, const std::vector &selected_cells) { - std::deque simd12, simd24; + std::deque simd12_add, simd12_sub; + std::deque simd24_add, simd24_sub; for (auto cell : selected_cells) { - if (!cell->type.in("$add")) + if (!cell->type.in("$add", "$sub")) continue; SigSpec Y = cell->getPort("\\Y"); if (!Y.is_chunk()) @@ -78,24 +79,26 @@ void pack_xilinx_simd(Module *module, const std::vector &selected_cells) continue; if (GetSize(B) > 12) continue; - simd12.push_back(cell); + if (cell->type == "$add") + simd12_add.push_back(cell); + else if (cell->type == "$sub") + simd12_sub.push_back(cell); } else if (GetSize(Y) <= 25) { if (GetSize(A) > 24) continue; if (GetSize(B) > 24) continue; - simd24.push_back(cell); + if (cell->type == "$add") + simd24_add.push_back(cell); + else if (cell->type == "$sub") + simd24_sub.push_back(cell); } else log_abort(); } - SigSpec AB; - SigSpec C; - SigSpec P; - SigSpec CARRYOUT; - auto f12 = [&AB,&C,&P,&CARRYOUT,module](Cell *lane) { + auto f12 = [module](SigSpec &AB, SigSpec &C, SigSpec &P, SigSpec &CARRYOUT, Cell *lane) { SigSpec A = lane->getPort("\\A"); SigSpec B = lane->getPort("\\B"); SigSpec Y = lane->getPort("\\Y"); @@ -110,84 +113,86 @@ void pack_xilinx_simd(Module *module, const std::vector &selected_cells) P.append(Y.extract(0, 12)); CARRYOUT.append(Y[12]); }; - while (simd12.size() > 1) { - AB = SigSpec(); - C = SigSpec(); - P = SigSpec(); - CARRYOUT = SigSpec(); - - Cell *lane1 = simd12.front(); - simd12.pop_front(); - Cell *lane2 = simd12.front(); - simd12.pop_front(); - Cell *lane3 = nullptr; - Cell *lane4 = nullptr; - - if (!simd12.empty()) { - lane3 = simd12.front(); + auto g12 = [&f12,module](std::deque &simd12) { + while (simd12.size() > 1) { + SigSpec AB, C, P, CARRYOUT; + + Cell *lane1 = simd12.front(); + simd12.pop_front(); + Cell *lane2 = simd12.front(); simd12.pop_front(); + Cell *lane3 = nullptr; + Cell *lane4 = nullptr; + if (!simd12.empty()) { - lane4 = simd12.front(); + lane3 = simd12.front(); simd12.pop_front(); + if (!simd12.empty()) { + lane4 = simd12.front(); + simd12.pop_front(); + } } - } - log("Analysing %s.%s for Xilinx DSP SIMD12 packing.\n", log_id(module), log_id(lane1)); - - Cell *cell = addDsp(module); - cell->setParam("\\USE_SIMD", Const("FOUR12")); - // X = A:B - // Y = 0 - // Z = C - cell->setPort("\\OPMODE", Const::from_string("0110011")); - - log_assert(lane1); - log_assert(lane2); - f12(lane1); - f12(lane2); - if (lane3) { - f12(lane3); - if (lane4) - f12(lane4); + log("Analysing %s.%s for Xilinx DSP SIMD12 packing.\n", log_id(module), log_id(lane1)); + + Cell *cell = addDsp(module); + cell->setParam("\\USE_SIMD", Const("FOUR12")); + // X = A:B + // Y = 0 + // Z = C + cell->setPort("\\OPMODE", Const::from_string("0110011")); + + log_assert(lane1); + log_assert(lane2); + f12(AB, C, P, CARRYOUT, lane1); + f12(AB, C, P, CARRYOUT, lane2); + if (lane3) { + f12(AB, C, P, CARRYOUT, lane3); + if (lane4) + f12(AB, C, P, CARRYOUT, lane4); + else { + AB.append(Const(0, 12)); + C.append(Const(0, 12)); + P.append(module->addWire(NEW_ID, 12)); + CARRYOUT.append(module->addWire(NEW_ID, 1)); + } + } else { - AB.append(Const(0, 12)); - C.append(Const(0, 12)); - P.append(module->addWire(NEW_ID, 12)); - CARRYOUT.append(module->addWire(NEW_ID, 1)); + AB.append(Const(0, 24)); + C.append(Const(0, 24)); + P.append(module->addWire(NEW_ID, 24)); + CARRYOUT.append(module->addWire(NEW_ID, 2)); } + log_assert(GetSize(AB) == 48); + log_assert(GetSize(C) == 48); + log_assert(GetSize(P) == 48); + log_assert(GetSize(CARRYOUT) == 4); + cell->setPort("\\A", AB.extract(18, 30)); + cell->setPort("\\B", AB.extract(0, 18)); + cell->setPort("\\C", C); + cell->setPort("\\P", P); + cell->setPort("\\CARRYOUT", CARRYOUT); + if (lane1->type == "$sub") + cell->setPort("\\ALUMODE", Const::from_string("0011")); + + module->remove(lane1); + module->remove(lane2); + if (lane3) module->remove(lane3); + if (lane4) module->remove(lane4); + + module->design->select(module, cell); } - else { - AB.append(Const(0, 24)); - C.append(Const(0, 24)); - P.append(module->addWire(NEW_ID, 24)); - CARRYOUT.append(module->addWire(NEW_ID, 2)); - } - log_assert(GetSize(AB) == 48); - log_assert(GetSize(C) == 48); - log_assert(GetSize(P) == 48); - log_assert(GetSize(CARRYOUT) == 4); - cell->setPort("\\A", AB.extract(18, 30)); - cell->setPort("\\B", AB.extract(0, 18)); - cell->setPort("\\C", C); - cell->setPort("\\P", P); - cell->setPort("\\CARRYOUT", CARRYOUT); - - module->remove(lane1); - module->remove(lane2); - if (lane3) module->remove(lane3); - if (lane4) module->remove(lane4); - - module->design->select(module, cell); - } + }; + g12(simd12_add); + g12(simd12_sub); - auto f24 = [&AB,&C,&P,&CARRYOUT,module](Cell *lane) { + auto f24 = [module](SigSpec &AB, SigSpec &C, SigSpec &P, SigSpec &CARRYOUT, Cell *lane) { SigSpec A = lane->getPort("\\A"); SigSpec B = lane->getPort("\\B"); SigSpec Y = lane->getPort("\\Y"); A.extend_u0(24, lane->getParam("\\A_SIGNED").as_bool()); B.extend_u0(24, lane->getParam("\\B_SIGNED").as_bool()); - AB.append(A); - C.append(B); + AB.append(B); if (GetSize(Y) < 25) Y.append(module->addWire(NEW_ID, 25-GetSize(Y))); else @@ -196,45 +201,51 @@ void pack_xilinx_simd(Module *module, const std::vector &selected_cells) CARRYOUT.append(module->addWire(NEW_ID)); // TWO24 uses every other bit CARRYOUT.append(Y[24]); }; - while (simd24.size() > 1) { - AB = SigSpec(); - C = SigSpec(); - P = SigSpec(); - CARRYOUT = SigSpec(); - - Cell *lane1 = simd24.front(); - simd24.pop_front(); - Cell *lane2 = simd24.front(); - simd24.pop_front(); - - log("Analysing %s.%s for Xilinx DSP SIMD24 packing.\n", log_id(module), log_id(lane1)); - - Cell *cell = addDsp(module); - cell->setParam("\\USE_SIMD", Const("TWO24")); - // X = A:B - // Y = 0 - // Z = C - cell->setPort("\\OPMODE", Const::from_string("0110011")); - - log_assert(lane1); - log_assert(lane2); - f24(lane1); - f24(lane2); - log_assert(GetSize(AB) == 48); - log_assert(GetSize(C) == 48); - log_assert(GetSize(P) == 48); - log_assert(GetSize(CARRYOUT) == 4); - cell->setPort("\\A", AB.extract(18, 30)); - cell->setPort("\\B", AB.extract(0, 18)); - cell->setPort("\\C", C); - cell->setPort("\\P", P); - cell->setPort("\\CARRYOUT", CARRYOUT); - - module->remove(lane1); - module->remove(lane2); - - module->design->select(module, cell); - } + auto g24 = [&f24,module](std::deque &simd24) { + while (simd24.size() > 1) { + SigSpec AB; + SigSpec C; + SigSpec P; + SigSpec CARRYOUT; + + Cell *lane1 = simd24.front(); + simd24.pop_front(); + Cell *lane2 = simd24.front(); + simd24.pop_front(); + + log("Analysing %s.%s for Xilinx DSP SIMD24 packing.\n", log_id(module), log_id(lane1)); + + Cell *cell = addDsp(module); + cell->setParam("\\USE_SIMD", Const("TWO24")); + // X = A:B + // Y = 0 + // Z = C + cell->setPort("\\OPMODE", Const::from_string("0110011")); + + log_assert(lane1); + log_assert(lane2); + f24(AB, C, P, CARRYOUT, lane1); + f24(AB, C, P, CARRYOUT, lane2); + log_assert(GetSize(AB) == 48); + log_assert(GetSize(C) == 48); + log_assert(GetSize(P) == 48); + log_assert(GetSize(CARRYOUT) == 4); + cell->setPort("\\A", AB.extract(18, 30)); + cell->setPort("\\B", AB.extract(0, 18)); + cell->setPort("\\C", C); + cell->setPort("\\P", P); + cell->setPort("\\CARRYOUT", CARRYOUT); + if (lane1->type == "$sub") + cell->setPort("\\ALUMODE", Const::from_string("0011")); + + module->remove(lane1); + module->remove(lane2); + + module->design->select(module, cell); + } + }; + g24(simd24_add); + g24(simd24_sub); } -- cgit v1.2.3 From cba63fe72b27c135e5fe04560d3a625e82c65fe3 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 9 Sep 2019 22:06:23 -0700 Subject: Oops --- passes/pmgen/xilinx_dsp.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 7bac1b974..d48c646c0 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -192,6 +192,7 @@ void pack_xilinx_simd(Module *module, const std::vector &selected_cells) SigSpec Y = lane->getPort("\\Y"); A.extend_u0(24, lane->getParam("\\A_SIGNED").as_bool()); B.extend_u0(24, lane->getParam("\\B_SIGNED").as_bool()); + C.append(A); AB.append(B); if (GetSize(Y) < 25) Y.append(module->addWire(NEW_ID, 25-GetSize(Y))); -- cgit v1.2.3 From d30b2a6d7eae08411ae588f1081b3b3793810678 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 10 Sep 2019 16:33:13 -0700 Subject: Update xilinx_dsp help text --- passes/pmgen/xilinx_dsp.cc | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index d48c646c0..40357a22d 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -480,19 +480,37 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) } struct XilinxDspPass : public Pass { - XilinxDspPass() : Pass("xilinx_dsp", "Xilinx: pack DSP registers") { } + XilinxDspPass() : Pass("xilinx_dsp", "Xilinx: pack resources into DSPs") { } void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" xilinx_dsp [options] [selection]\n"); log("\n"); - log("Pack registers into Xilinx DSPs\n"); + log("Pack input registers (A, B, C, D, AD; with optional enable), pipeline registers\n"); + log("(M; with optional enable), output registers (P; with optional enable),\n"); + log("pre-adder and/or post-adder into Xilinx DSP resources.\n"); + log("\n"); + log("Multiply-accumulate operations using the post-adder with feedback on the 'C'\n"); + log("input will be folded into the DSP. In this scenario only, the 'C' input can be\n"); + log("used to override the existing accumulation result with a new value.\n"); + log("\n"); + log("'PCOUT' -> 'PCIN' cascading is detected for 'P' -> 'C' connections, where 'P' is\n"); + log("is right-shifted by 18-bits and used as an input to the post-adder (a common\n"); + log("pattern for summing partial products).\n"); + log("\n"); + log("Not currently supported: reset (RST*) inputs on any register.\n"); + log("\n"); + log("\n"); + log("Experimental feature: addition/subtractions less than 12 or 24 bits with the\n"); + log("'(* use_dsp=\"simd\" *)' attribute attached to the output wire or attached to\n"); + log("the add/subtract operator will cause those operations to be implemented using\n"); + log("the 'SIMD' feature of DSPs.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { - log_header(design, "Executing XILINX_DSP pass (pack DSPs).\n"); + log_header(design, "Executing XILINX_DSP pass (pack resources into DSPs).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) -- cgit v1.2.3 From e64e650f9c077094e7fd15c7e149f5b9ec4773d7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 10 Sep 2019 16:35:10 -0700 Subject: Update help text --- passes/pmgen/xilinx_dsp.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 40357a22d..3e4d596ca 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -495,9 +495,9 @@ struct XilinxDspPass : public Pass { log("input will be folded into the DSP. In this scenario only, the 'C' input can be\n"); log("used to override the existing accumulation result with a new value.\n"); log("\n"); - log("'PCOUT' -> 'PCIN' cascading is detected for 'P' -> 'C' connections, where 'P' is\n"); - log("is right-shifted by 18-bits and used as an input to the post-adder (a common\n"); - log("pattern for summing partial products).\n"); + log("Use of the dedicated 'PCOUT' -> 'PCIN' path is detected for 'P' -> 'C' connections\n"); + log("where 'P' is right-shifted by 18-bits and used as an input to the post-adder (a\n"); + log("pattern common for summing partial products to implement wide multiplies).\n"); log("\n"); log("Not currently supported: reset (RST*) inputs on any register.\n"); log("\n"); -- cgit v1.2.3 From 8b8a68b38a43a082b76747934d98c6e488d1f6e4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 10 Sep 2019 18:27:05 -0700 Subject: Refactor MREG and PREG to out_dffe subpattern --- passes/pmgen/xilinx_dsp.pmg | 277 +++++++++++++++++++------------------------- 1 file changed, 122 insertions(+), 155 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 07432dfc7..09e59c184 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -7,12 +7,12 @@ state postAddAB postAddMuxAB state ffAenpol ffADenpol ffBenpol ffCenpol ffDenpol ffMenpol ffPenpol state ffPoffset -state ffAD ffADmux ffA ffAmux ffB ffBmux ffC ffCmux ffD ffDmux +state ffAD ffADmux ffA ffAmux ffB ffBmux ffC ffCmux ffD ffDmux ffM ffMmux ffP ffPmux // subpattern -state argQ +state argQ argD state ffenpol -udata dffD +udata dffD dffQ udata dffclock udata dff dffmux udata dffenpol @@ -159,76 +159,20 @@ code argQ ffD ffDmux ffDenpol sigD clock } endcode -match ffMmux - if param(dsp, \MREG).as_int() == 0 - if dsp->parameters.at(\USE_MULT, Const("MULTIPLY")).decode_string() == "MULTIPLY" - if nusers(sigM) == 2 - select ffMmux->type.in($mux) - choice BA {\B, \A} - // new-value net must have exactly two users: dsp and ffMmux - select nusers(port(ffMmux, BA)) == 2 - define AB (BA == \B ? \A : \B) - // keep-last-value net must have at least three users: ffMmux, ffM, downstream sink(s) - select nusers(port(ffMmux, AB)) >= 3 - // ffMmux output must have two users: ffMmux and ffM.D - select nusers(port(ffMmux, \Y)) == 2 - filter GetSize(unextend(port(ffMmux, BA))) <= GetSize(sigM) - filter unextend(port(ffMmux, BA)) == sigM.extract(0, GetSize(unextend(port(ffMmux, BA)))) - // Remaining bits on sigM must not have any other users - filter nusers(sigM.extract_end(GetSize(unextend(port(ffMmux, BA))))) <= 1 - define pol (AB == \A) - set ffMenpol pol - optional -endmatch - -code sigM - if (ffMmux) - sigM = port(ffMmux, \Y); -endcode - -match ffM_enable - if ffMmux - if nusers(sigM) == 2 - select ffM_enable->type.in($dff) - // DSP48E1 does not support clock inversion - select param(ffM_enable, \CLK_POLARITY).as_bool() - index port(ffM_enable, \D) === sigM - index port(ffM_enable, \Q) === port(ffMmux, ffMenpol ? \A : \B) -endmatch - -match ffM - if dsp->parameters.at(\USE_MULT, Const("MULTIPLY")).decode_string() == "MULTIPLY" - if !ffM_enable - if param(dsp, \MREG).as_int() == 0 - if nusers(sigM) == 2 - select ffM->type.in($dff) - // DSP48E1 does not support clock inversion - select param(ffM, \CLK_POLARITY).as_bool() - index port(ffM, \D) === sigM - optional -endmatch - -code ffM clock sigM sigP - if (ffM_enable) { - log_assert(!ffM); - ffM = ffM_enable; - } - if (ffM) { - sigM = port(ffM, \Q); - - for (auto b : sigM) - if (b.wire->get_bool_attribute(\keep)) - reject; - - SigBit c = port(ffM, \CLK).as_bit(); - if (clock != SigBit() && c != clock) - reject; - clock = c; +code argD ffM ffMmux ffMenpol sigM sigP clock + if (param(dsp, \MREG).as_int() == 0 && nusers(sigM) == 2) { + argD = sigM; + subpattern(out_dffe); + if (dff) { + ffM = dff; + clock = dffclock; + if (dffmux) { + ffMmux = dffmux; + ffMenpol = dffenpol; + } + sigM = dffQ; + } } - // No enable mux possible without flop - else if (ffMmux) - reject; - sigP = sigM; endcode @@ -268,90 +212,25 @@ code sigC sigP } endcode -match ffPmux - if param(dsp, \PREG).as_int() == 0 - // If ffMmux and no postAdd new-value net must have exactly three users: ffMmux, ffM and ffPmux - if !ffMmux || postAdd || nusers(sigP) == 3 - // Otherwise new-value net must have exactly two users: dsp and ffPmux - if (ffMmux && !postAdd) || nusers(sigP) == 2 - - select ffPmux->type.in($mux) - // ffPmux output must have two users: ffPmux and ffP.D - select nusers(port(ffPmux, \Y)) == 2 - filter GetSize(port(ffPmux, \Y)) >= GetSize(sigP) - - slice offset GetSize(port(ffPmux, \Y)) - filter offset+GetSize(sigP) <= GetSize(port(ffPmux, \Y)) - choice BA {\B, \A} - filter port(ffPmux, BA).extract(offset, GetSize(sigP)) == sigP - - define AB (BA == \B ? \A : \B) - // keep-last-value net must have at least three users: ffPmux, ffP, downstream sink(s) - filter nusers(port(ffPmux, AB)) >= 3 - define pol (AB == \A) - set ffPenpol pol - set ffPoffset offset - optional -endmatch - -code sigP - if (ffPmux) - sigP.replace(port(ffPmux, ffPenpol ? \B : \A), port(ffPmux, \Y)); -endcode - -match ffP_enable - if ffPmux - if nusers(sigP) == 2 - select ffP_enable->type.in($dff) - // DSP48E1 does not support clock inversion - select param(ffP_enable, \CLK_POLARITY).as_bool() - index port(ffP_enable, \D) === port(ffPmux, \Y) - index port(ffP_enable, \Q) === port(ffPmux, ffPenpol ? \A : \B) - filter GetSize(port(ffP_enable, \D)) >= GetSize(sigP) - filter ffPoffset+GetSize(sigP) <= GetSize(port(ffP_enable, \D)) - filter port(ffP_enable, \D).extract(ffPoffset, GetSize(sigP)) == sigP -endmatch - -match ffP - if !ffP_enable - if param(dsp, \PREG).as_int() == 0 - // If ffMmux and no postAdd new-value net must have exactly three users: ffMmux, ffM and ffPmux - if !ffMmux || postAdd || nusers(sigP) == 3 - // Otherwise new-value net must have exactly two users: dsp and ffPmux - if (ffMmux && !postAdd) || nusers(sigP) == 2 - - select ffP->type.in($dff) - // DSP48E1 does not support clock inversion - select param(ffP, \CLK_POLARITY).as_bool() - filter GetSize(port(ffP, \D)) >= GetSize(sigP) - slice offset GetSize(port(ffP, \D)) - filter offset+GetSize(sigP) <= GetSize(port(ffP, \D)) - filter port(ffP, \D).extract(offset, GetSize(sigP)) == sigP - optional -endmatch - -code ffP sigP clock - if (ffP_enable) { - log_assert(!ffP); - ffP = ffP_enable; - } - if (ffP) { - for (auto b : port(ffP, \Q)) - if (b.wire->get_bool_attribute(\keep)) - reject; - - SigBit c = port(ffP, \CLK).as_bit(); - - if (clock != SigBit() && c != clock) - reject; - - clock = c; - - sigP.replace(port(ffP, \D), port(ffP, \Q)); +code argD ffP ffPmux ffPenpol sigP clock + if (param(dsp, \PREG).as_int() == 0) { + // If ffMmux and no postAdd new-value net must have exactly three users: ffMmux, ffM and ffPmux + if ((ffMmux && !postAdd && nusers(sigP) == 3) || + // Otherwise new-value net must have exactly two users: dsp and ffPmux + ((!ffMmux || postAdd) && nusers(sigP) == 2)) { + argD = sigP; + subpattern(out_dffe); + if (dff) { + ffP = dff; + clock = dffclock; + if (dffmux) { + ffPmux = dffmux; + ffPenpol = dffenpol; + } + sigP = dffQ; + } + } } - // No enable mux possible without flop - else if (ffPmux) - reject; endcode match postAddMux @@ -391,6 +270,8 @@ code accept; endcode +// ####################### + subpattern in_dffe arg argQ clock ffenpol @@ -457,3 +338,89 @@ code else dffmux = nullptr; endcode + +// ####################### + +subpattern out_dffe +arg argD clock ffenpol +arg unextend + +match ffmux + select ffmux->type.in($mux) + // ffmux output must have two users: ffmux and ff.D + select nusers(port(ffmux, \Y)) == 2 + filter GetSize(port(ffmux, \Y)) >= GetSize(argD) + + choice BA {\B, \A} + // new-value net must have exactly two users: (upstream) and ffmux + select nusers(port(ffmux, BA)) == 2 + + slice offset GetSize(port(ffmux, \Y)) + filter offset+GetSize(argD) <= GetSize(port(ffmux, \Y)) + filter port(ffmux, BA).extract(offset, GetSize(argD)) == argD + + define AB (BA == \B ? \A : \B) + // keep-last-value net must have at least three users: ffmux, ff, downstream sink(s) + select nusers(port(ffmux, AB)) >= 3 + + filter GetSize(unextend(port(ffmux, BA))) <= GetSize(argD) + filter unextend(port(ffmux, BA)) == argD.extract(0, GetSize(unextend(port(ffmux, BA)))) + // Remaining bits on argD must not have any other users + filter nusers(argD.extract_end(GetSize(unextend(port(ffmux, BA))))) <= 1 + + define pol (AB == \A) + set ffenpol pol + semioptional +endmatch + +code argD + if (ffmux) { + dffmux = ffmux; + dffenpol = ffenpol; + argD = port(ffmux, \Y); + } + else + dffmux = nullptr; +endcode + +match ff_enable + if ffmux + select ff_enable->type.in($dff) + // DSP48E1 does not support clock inversion + select param(ff_enable, \CLK_POLARITY).as_bool() + index port(ff_enable, \D) === argD + index port(ff_enable, \Q) === port(ffmux, ffenpol ? \A : \B) +endmatch + +match ff + if !ff_enable + select ff->type.in($dff) + // DSP48E1 does not support clock inversion + select param(ff, \CLK_POLARITY).as_bool() + index port(ff, \D) === argD + semioptional +endmatch + +code + if (ff_enable) + dff = ff_enable; + else + dff = ff; + log_dump("ffM", dff, dffmux); + if (dff) { + dffQ = port(dff, \Q); + + for (auto b : dffQ) + if (b.wire->get_bool_attribute(\keep)) + reject; + + if (clock != SigBit()) { + if (port(dff, \CLK) != clock) + reject; + } + dffclock = port(dff, \CLK); + } + // No enable mux possible without flop + else if (ffmux) + reject; +endcode -- cgit v1.2.3 From 86700c2beaa4cf8f5142c55f143b5b0d2207d953 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 10 Sep 2019 18:52:54 -0700 Subject: d?ffmux -> d?ffcemux --- passes/pmgen/xilinx_dsp.pmg | 67 ++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 34 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 09e59c184..9d6236d07 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -14,7 +14,7 @@ state argQ argD state ffenpol udata dffD dffQ udata dffclock -udata dff dffmux +udata dff dffcemux udata dffenpol match dsp @@ -60,8 +60,8 @@ code argQ ffAD ffADmux ffADenpol sigA clock if (dff) { ffAD = dff; clock = dffclock; - if (dffmux) { - ffADmux = dffmux; + if (dffcemux) { + ffADmux = dffcemux; ffADenpol = dffenpol; } sigA = dffD; @@ -109,8 +109,8 @@ code argQ ffA ffAmux ffAenpol sigA clock ffAD ffADmux ffADenpol if (dff) { ffA = dff; clock = dffclock; - if (dffmux) { - ffAmux = dffmux; + if (dffcemux) { + ffAmux = dffcemux; ffAenpol = dffenpol; } sigA = dffD; @@ -134,8 +134,8 @@ code argQ ffB ffBmux ffBenpol sigB clock if (dff) { ffB = dff; clock = dffclock; - if (dffmux) { - ffBmux = dffmux; + if (dffcemux) { + ffBmux = dffcemux; ffBenpol = dffenpol; } sigB = dffD; @@ -150,8 +150,8 @@ code argQ ffD ffDmux ffDenpol sigD clock if (dff) { ffD = dff; clock = dffclock; - if (dffmux) { - ffDmux = dffmux; + if (dffcemux) { + ffDmux = dffcemux; ffDenpol = dffenpol; } sigD = dffD; @@ -166,8 +166,8 @@ code argD ffM ffMmux ffMenpol sigM sigP clock if (dff) { ffM = dff; clock = dffclock; - if (dffmux) { - ffMmux = dffmux; + if (dffcemux) { + ffMmux = dffcemux; ffMenpol = dffenpol; } sigM = dffQ; @@ -223,8 +223,8 @@ code argD ffP ffPmux ffPenpol sigP clock if (dff) { ffP = dff; clock = dffclock; - if (dffmux) { - ffPmux = dffmux; + if (dffcemux) { + ffPmux = dffcemux; ffPenpol = dffenpol; } sigP = dffQ; @@ -257,8 +257,8 @@ code argQ ffC ffCmux ffCenpol sigC clock if (dff) { ffC = dff; clock = dffclock; - if (dffmux) { - ffCmux = dffmux; + if (dffcemux) { + ffCmux = dffcemux; ffCenpol = dffenpol; } sigC = dffD; @@ -301,9 +301,9 @@ code argQ dff = ff; dffD = argQ; dffD.replace(port(ff, \Q), port(ff, \D)); - // Only search for ffmux if ff.Q has at - // least 3 users (ff, dsp, ffmux) and - // its ff.D only has two (ff, ffmux) + // Only search for ffcemux if argQ has at + // least 3 users (ff, , ffcemux) and + // its ff.D only has two (ff, ffcemux) if (!(nusers(argQ) >= 3 && nusers(dffD) == 2)) argQ = SigSpec(); } @@ -313,30 +313,30 @@ code argQ } endcode -match ffmux +match ffcemux if !argQ.empty() - select ffmux->type.in($mux) - index port(ffmux, \Y) === port(ff, \D) - filter GetSize(port(ffmux, \Y)) >= GetSize(dffD) - slice offset GetSize(port(ffmux, \Y)) - filter offset+GetSize(dffD) <= GetSize(port(ffmux, \Y)) - filter port(ffmux, \Y).extract(offset, GetSize(dffD)) == dffD + select ffcemux->type.in($mux) + index port(ffcemux, \Y) === port(ff, \D) + filter GetSize(port(ffcemux, \Y)) >= GetSize(dffD) + slice offset GetSize(port(ffcemux, \Y)) + filter offset+GetSize(dffD) <= GetSize(port(ffcemux, \Y)) + filter port(ffcemux, \Y).extract(offset, GetSize(dffD)) == dffD choice AB {\A, \B} - filter offset+GetSize(argQ) <= GetSize(port(ffmux, \Y)) - filter port(ffmux, AB).extract(offset, GetSize(argQ)) == argQ + filter offset+GetSize(argQ) <= GetSize(port(ffcemux, \Y)) + filter port(ffcemux, AB).extract(offset, GetSize(argQ)) == argQ define pol (AB == \A) set ffenpol pol semioptional endmatch code - if (ffmux) { - dffmux = ffmux; + if (ffcemux) { + dffcemux = ffcemux; dffenpol = ffenpol; - dffD = port(ffmux, dffenpol ? \B : \A); + dffD = port(ffcemux, dffenpol ? \B : \A); } else - dffmux = nullptr; + dffcemux = nullptr; endcode // ####################### @@ -375,12 +375,12 @@ endmatch code argD if (ffmux) { - dffmux = ffmux; + dffcemux = ffmux; dffenpol = ffenpol; argD = port(ffmux, \Y); } else - dffmux = nullptr; + dffcemux = nullptr; endcode match ff_enable @@ -406,7 +406,6 @@ code dff = ff_enable; else dff = ff; - log_dump("ffM", dff, dffmux); if (dff) { dffQ = port(dff, \Q); -- cgit v1.2.3 From c6df55a9e7c9827a6b971cc885b83fdb69b269d3 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 10 Sep 2019 18:59:03 -0700 Subject: enpol -> cepol --- passes/pmgen/xilinx_dsp.cc | 22 +++++------ passes/pmgen/xilinx_dsp.pmg | 94 +++++++++++++++++++++++---------------------- 2 files changed, 59 insertions(+), 57 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 3e4d596ca..a5fa67083 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -297,7 +297,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) if (st.ffAD) { if (st.ffADmux) { SigSpec S = st.ffADmux->getPort("\\S"); - cell->setPort("\\CEAD", st.ffADenpol ? S : pm.module->Not(NEW_ID, S)); + cell->setPort("\\CEAD", st.ffADcepol ? S : pm.module->Not(NEW_ID, S)); } else cell->setPort("\\CEAD", State::S1); @@ -346,10 +346,10 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) A.replace(Q, D); if (st.ffAmux) { SigSpec Y = st.ffAmux->getPort("\\Y"); - SigSpec AB = st.ffAmux->getPort(st.ffAenpol ? "\\B" : "\\A"); + SigSpec AB = st.ffAmux->getPort(st.ffAcepol ? "\\B" : "\\A"); SigSpec S = st.ffAmux->getPort("\\S"); A.replace(Y, AB); - cell->setPort("\\CEA2", st.ffAenpol ? S : pm.module->Not(NEW_ID, S)); + cell->setPort("\\CEA2", st.ffAcepol ? S : pm.module->Not(NEW_ID, S)); } else cell->setPort("\\CEA2", State::S1); @@ -364,10 +364,10 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) B.replace(Q, D); if (st.ffBmux) { SigSpec Y = st.ffBmux->getPort("\\Y"); - SigSpec AB = st.ffBmux->getPort(st.ffBenpol ? "\\B" : "\\A"); + SigSpec AB = st.ffBmux->getPort(st.ffBcepol ? "\\B" : "\\A"); SigSpec S = st.ffBmux->getPort("\\S"); B.replace(Y, AB); - cell->setPort("\\CEB2", st.ffBenpol ? S : pm.module->Not(NEW_ID, S)); + cell->setPort("\\CEB2", st.ffBcepol ? S : pm.module->Not(NEW_ID, S)); } else cell->setPort("\\CEB2", State::S1); @@ -383,11 +383,11 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) if (st.ffCmux) { SigSpec Y = st.ffCmux->getPort("\\Y"); - SigSpec AB = st.ffCmux->getPort(st.ffCenpol ? "\\B" : "\\A"); + SigSpec AB = st.ffCmux->getPort(st.ffCcepol ? "\\B" : "\\A"); SigSpec S = st.ffCmux->getPort("\\S"); C.replace(Y, AB); - cell->setPort("\\CEC", st.ffCenpol ? S : pm.module->Not(NEW_ID, S)); + cell->setPort("\\CEC", st.ffCcepol ? S : pm.module->Not(NEW_ID, S)); } else cell->setPort("\\CEC", State::S1); @@ -403,11 +403,11 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) if (st.ffDmux) { SigSpec Y = st.ffDmux->getPort("\\Y"); - SigSpec AB = st.ffDmux->getPort(st.ffDenpol ? "\\B" : "\\A"); + SigSpec AB = st.ffDmux->getPort(st.ffDcepol ? "\\B" : "\\A"); SigSpec S = st.ffDmux->getPort("\\S"); D_.replace(Y, AB); - cell->setPort("\\CED", st.ffDenpol ? S : pm.module->Not(NEW_ID, S)); + cell->setPort("\\CED", st.ffDcepol ? S : pm.module->Not(NEW_ID, S)); } else cell->setPort("\\CED", State::S1); @@ -418,7 +418,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) if (st.ffM) { if (st.ffMmux) { SigSpec S = st.ffMmux->getPort("\\S"); - cell->setPort("\\CEM", st.ffMenpol ? S : pm.module->Not(NEW_ID, S)); + cell->setPort("\\CEM", st.ffMcepol ? S : pm.module->Not(NEW_ID, S)); pm.autoremove(st.ffMmux); } else @@ -433,7 +433,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) if (st.ffP) { if (st.ffPmux) { SigSpec S = st.ffPmux->getPort("\\S"); - cell->setPort("\\CEP", st.ffPenpol ? S : pm.module->Not(NEW_ID, S)); + cell->setPort("\\CEP", st.ffPcepol ? S : pm.module->Not(NEW_ID, S)); st.ffPmux->connections_.at("\\Y").replace(P, pm.module->addWire(NEW_ID, GetSize(P))); } else diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 9d6236d07..ee9ea1312 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -4,18 +4,19 @@ state > unextend state clock state sigA sigffAmuxY sigB sigffBmuxY sigC sigffCmuxY sigD sigffDmuxY sigM sigP state postAddAB postAddMuxAB -state ffAenpol ffADenpol ffBenpol ffCenpol ffDenpol ffMenpol ffPenpol +state ffAcepol ffADcepol ffBcepol ffCcepol ffDcepol ffMcepol ffPcepol state ffPoffset state ffAD ffADmux ffA ffAmux ffB ffBmux ffC ffCmux ffD ffDmux ffM ffMmux ffP ffPmux // subpattern state argQ argD -state ffenpol +state ffcepol +state ffmux udata dffD dffQ udata dffclock udata dff dffcemux -udata dffenpol +udata dffcepol match dsp select dsp->type.in(\DSP48E1) @@ -53,7 +54,7 @@ code unextend sigA sigB sigC sigD sigM sigM = P; endcode -code argQ ffAD ffADmux ffADenpol sigA clock +code argQ ffAD ffADmux ffADcepol sigA clock if (param(dsp, \ADREG).as_int() == 0) { argQ = sigA; subpattern(in_dffe); @@ -62,7 +63,7 @@ code argQ ffAD ffADmux ffADenpol sigA clock clock = dffclock; if (dffcemux) { ffADmux = dffcemux; - ffADenpol = dffenpol; + ffADcepol = dffcepol; } sigA = dffD; } @@ -99,7 +100,7 @@ code sigA sigD } endcode -code argQ ffA ffAmux ffAenpol sigA clock ffAD ffADmux ffADenpol +code argQ ffA ffAmux ffAcepol sigA clock ffAD ffADmux ffADcepol // Only search for ffA if there was a pre-adder // (otherwise ffA would have been matched as ffAD) if (preAdd) { @@ -111,7 +112,7 @@ code argQ ffA ffAmux ffAenpol sigA clock ffAD ffADmux ffADenpol clock = dffclock; if (dffcemux) { ffAmux = dffcemux; - ffAenpol = dffenpol; + ffAcepol = dffcepol; } sigA = dffD; } @@ -123,11 +124,11 @@ code argQ ffA ffAmux ffAenpol sigA clock ffAD ffADmux ffADenpol log_assert(!ffA && !ffAmux); std::swap(ffA, ffAD); std::swap(ffAmux, ffADmux); - ffAenpol = ffADenpol; + ffAcepol = ffADcepol; } endcode -code argQ ffB ffBmux ffBenpol sigB clock +code argQ ffB ffBmux ffBcepol sigB clock if (param(dsp, \BREG).as_int() == 0) { argQ = sigB; subpattern(in_dffe); @@ -136,14 +137,14 @@ code argQ ffB ffBmux ffBenpol sigB clock clock = dffclock; if (dffcemux) { ffBmux = dffcemux; - ffBenpol = dffenpol; + ffBcepol = dffcepol; } sigB = dffD; } } endcode -code argQ ffD ffDmux ffDenpol sigD clock +code argQ ffD ffDmux ffDcepol sigD clock if (param(dsp, \DREG).as_int() == 0) { argQ = sigD; subpattern(in_dffe); @@ -152,14 +153,14 @@ code argQ ffD ffDmux ffDenpol sigD clock clock = dffclock; if (dffcemux) { ffDmux = dffcemux; - ffDenpol = dffenpol; + ffDcepol = dffcepol; } sigD = dffD; } } endcode -code argD ffM ffMmux ffMenpol sigM sigP clock +code argD ffM ffMmux ffMcepol sigM sigP clock if (param(dsp, \MREG).as_int() == 0 && nusers(sigM) == 2) { argD = sigM; subpattern(out_dffe); @@ -168,7 +169,7 @@ code argD ffM ffMmux ffMenpol sigM sigP clock clock = dffclock; if (dffcemux) { ffMmux = dffcemux; - ffMenpol = dffenpol; + ffMcepol = dffcepol; } sigM = dffQ; } @@ -212,7 +213,7 @@ code sigC sigP } endcode -code argD ffP ffPmux ffPenpol sigP clock +code argD ffP ffPmux ffPcepol sigP clock if (param(dsp, \PREG).as_int() == 0) { // If ffMmux and no postAdd new-value net must have exactly three users: ffMmux, ffM and ffPmux if ((ffMmux && !postAdd && nusers(sigP) == 3) || @@ -225,7 +226,7 @@ code argD ffP ffPmux ffPenpol sigP clock clock = dffclock; if (dffcemux) { ffPmux = dffcemux; - ffPenpol = dffenpol; + ffPcepol = dffcepol; } sigP = dffQ; } @@ -250,7 +251,7 @@ code sigC sigC = port(postAddMux, postAddMuxAB == \A ? \B : \A); endcode -code argQ ffC ffCmux ffCenpol sigC clock +code argQ ffC ffCmux ffCcepol sigC clock if (param(dsp, \CREG).as_int() == 0) { argQ = sigC; subpattern(in_dffe); @@ -259,7 +260,7 @@ code argQ ffC ffCmux ffCenpol sigC clock clock = dffclock; if (dffcemux) { ffCmux = dffcemux; - ffCenpol = dffenpol; + ffCcepol = dffcepol; } sigC = dffD; } @@ -273,7 +274,7 @@ endcode // ####################### subpattern in_dffe -arg argQ clock ffenpol +arg argQ clock ffcepol match ff select ff->type.in($dff) @@ -325,15 +326,15 @@ match ffcemux filter offset+GetSize(argQ) <= GetSize(port(ffcemux, \Y)) filter port(ffcemux, AB).extract(offset, GetSize(argQ)) == argQ define pol (AB == \A) - set ffenpol pol + set ffcepol pol semioptional endmatch code if (ffcemux) { dffcemux = ffcemux; - dffenpol = ffenpol; - dffD = port(ffcemux, dffenpol ? \B : \A); + dffcepol = ffcepol; + dffD = port(ffcemux, dffcepol ? \B : \A); } else dffcemux = nullptr; @@ -342,42 +343,43 @@ endcode // ####################### subpattern out_dffe -arg argD clock ffenpol -arg unextend +arg argD clock ffcepol +arg unextend ffmux -match ffmux - select ffmux->type.in($mux) - // ffmux output must have two users: ffmux and ff.D - select nusers(port(ffmux, \Y)) == 2 - filter GetSize(port(ffmux, \Y)) >= GetSize(argD) +match ffcemux + select ffcemux->type.in($mux) + // ffcemux output must have two users: ffcemux and ff.D + select nusers(port(ffcemux, \Y)) == 2 + filter GetSize(port(ffcemux, \Y)) >= GetSize(argD) choice BA {\B, \A} - // new-value net must have exactly two users: (upstream) and ffmux - select nusers(port(ffmux, BA)) == 2 + // new-value net must have exactly two users: (upstream) and ffcemux + select nusers(port(ffcemux, BA)) == 2 - slice offset GetSize(port(ffmux, \Y)) - filter offset+GetSize(argD) <= GetSize(port(ffmux, \Y)) - filter port(ffmux, BA).extract(offset, GetSize(argD)) == argD + slice offset GetSize(port(ffcemux, \Y)) + filter offset+GetSize(argD) <= GetSize(port(ffcemux, \Y)) + filter port(ffcemux, BA).extract(offset, GetSize(argD)) == argD define AB (BA == \B ? \A : \B) - // keep-last-value net must have at least three users: ffmux, ff, downstream sink(s) - select nusers(port(ffmux, AB)) >= 3 + // keep-last-value net must have at least three users: ffcemux, ff, downstream sink(s) + select nusers(port(ffcemux, AB)) >= 3 - filter GetSize(unextend(port(ffmux, BA))) <= GetSize(argD) - filter unextend(port(ffmux, BA)) == argD.extract(0, GetSize(unextend(port(ffmux, BA)))) + filter GetSize(unextend(port(ffcemux, BA))) <= GetSize(argD) + filter unextend(port(ffcemux, BA)) == argD.extract(0, GetSize(unextend(port(ffcemux, BA)))) // Remaining bits on argD must not have any other users - filter nusers(argD.extract_end(GetSize(unextend(port(ffmux, BA))))) <= 1 + filter nusers(argD.extract_end(GetSize(unextend(port(ffcemux, BA))))) <= 1 define pol (AB == \A) - set ffenpol pol + set ffcepol pol semioptional endmatch -code argD - if (ffmux) { - dffcemux = ffmux; - dffenpol = ffenpol; - argD = port(ffmux, \Y); +code argD ffmux + if (ffcemux) { + dffcemux = ffcemux; + dffcepol = ffcepol; + argD = port(ffcemux, \Y); + ffmux = ffcemux; } else dffcemux = nullptr; @@ -389,7 +391,7 @@ match ff_enable // DSP48E1 does not support clock inversion select param(ff_enable, \CLK_POLARITY).as_bool() index port(ff_enable, \D) === argD - index port(ff_enable, \Q) === port(ffmux, ffenpol ? \A : \B) + index port(ff_enable, \Q) === port(ffmux, ffcepol ? \A : \B) endmatch match ff -- cgit v1.2.3 From af147d14300a8fbff2db8d823cf3622ec5a81ca6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 10 Sep 2019 20:51:48 -0700 Subject: Add support for RSTP --- passes/pmgen/xilinx_dsp.cc | 16 ++++++--- passes/pmgen/xilinx_dsp.pmg | 80 ++++++++++++++++++++++++++++++++------------- 2 files changed, 70 insertions(+), 26 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index a5fa67083..fe82b1307 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -273,7 +273,8 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("postAdd: %s\n", log_id(st.postAdd, "--")); log("postAddMux: %s\n", log_id(st.postAddMux, "--")); log("ffP: %s\n", log_id(st.ffP, "--")); - log("ffPmux: %s\n", log_id(st.ffPmux, "--")); + log("ffPcemux: %s\n", log_id(st.ffPcemux, "--")); + log("ffPrstmux: %s\n", log_id(st.ffPrstmux, "--")); #endif log("Analysing %s.%s for Xilinx DSP packing.\n", log_id(pm.module), log_id(st.dsp)); @@ -431,10 +432,17 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) pm.autoremove(st.ffM); } if (st.ffP) { - if (st.ffPmux) { - SigSpec S = st.ffPmux->getPort("\\S"); + if (st.ffPrstmux) { + SigSpec S = st.ffPrstmux->getPort("\\S"); + cell->setPort("\\RSTP", st.ffPrstpol ? S : pm.module->Not(NEW_ID, S)); + st.ffPrstmux->connections_.at("\\Y").replace(P, pm.module->addWire(NEW_ID, GetSize(P))); + } + else + cell->setPort("\\RSTP", State::S1); + if (st.ffPcemux) { + SigSpec S = st.ffPcemux->getPort("\\S"); cell->setPort("\\CEP", st.ffPcepol ? S : pm.module->Not(NEW_ID, S)); - st.ffPmux->connections_.at("\\Y").replace(P, pm.module->addWire(NEW_ID, GetSize(P))); + st.ffPcemux->connections_.at("\\Y").replace(P, pm.module->addWire(NEW_ID, GetSize(P))); } else cell->setPort("\\CEP", State::S1); diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index ee9ea1312..05837d057 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -4,19 +4,18 @@ state > unextend state clock state sigA sigffAmuxY sigB sigffBmuxY sigC sigffCmuxY sigD sigffDmuxY sigM sigP state postAddAB postAddMuxAB -state ffAcepol ffADcepol ffBcepol ffCcepol ffDcepol ffMcepol ffPcepol +state ffAcepol ffADcepol ffBcepol ffCcepol ffDcepol ffMcepol ffPcepol ffPrstpol state ffPoffset -state ffAD ffADmux ffA ffAmux ffB ffBmux ffC ffCmux ffD ffDmux ffM ffMmux ffP ffPmux +state ffAD ffADmux ffA ffAmux ffB ffBmux ffC ffCmux ffD ffDmux ffM ffMmux ffP ffPcemux ffPrstmux // subpattern state argQ argD -state ffcepol -state ffmux +state ffcepol ffrstpol udata dffD dffQ udata dffclock -udata dff dffcemux -udata dffcepol +udata dff dffcemux dffrstmux +udata dffcepol dffrstpol match dsp select dsp->type.in(\DSP48E1) @@ -213,11 +212,11 @@ code sigC sigP } endcode -code argD ffP ffPmux ffPcepol sigP clock +code argD ffP ffPcemux ffPrstmux ffPcepol ffPrstpol sigP clock if (param(dsp, \PREG).as_int() == 0) { - // If ffMmux and no postAdd new-value net must have exactly three users: ffMmux, ffM and ffPmux + // If ffMmux and no postAdd new-value net must have exactly three users: ffMmux, ffM and ffPcemux if ((ffMmux && !postAdd && nusers(sigP) == 3) || - // Otherwise new-value net must have exactly two users: dsp and ffPmux + // Otherwise new-value net must have exactly two users: dsp and ffPcemux ((!ffMmux || postAdd) && nusers(sigP) == 2)) { argD = sigP; subpattern(out_dffe); @@ -225,8 +224,10 @@ code argD ffP ffPmux ffPcepol sigP clock ffP = dff; clock = dffclock; if (dffcemux) { - ffPmux = dffcemux; + ffPcemux = dffcemux; ffPcepol = dffcepol; + ffPrstmux = dffrstmux; + ffPrstpol = dffrstpol; } sigP = dffQ; } @@ -343,8 +344,8 @@ endcode // ####################### subpattern out_dffe -arg argD clock ffcepol -arg unextend ffmux +arg argD argQ clock +arg unextend match ffcemux select ffcemux->type.in($mux) @@ -356,14 +357,11 @@ match ffcemux // new-value net must have exactly two users: (upstream) and ffcemux select nusers(port(ffcemux, BA)) == 2 - slice offset GetSize(port(ffcemux, \Y)) - filter offset+GetSize(argD) <= GetSize(port(ffcemux, \Y)) - filter port(ffcemux, BA).extract(offset, GetSize(argD)) == argD - define AB (BA == \B ? \A : \B) // keep-last-value net must have at least three users: ffcemux, ff, downstream sink(s) select nusers(port(ffcemux, AB)) >= 3 + slice offset GetSize(port(ffcemux, \Y)) filter GetSize(unextend(port(ffcemux, BA))) <= GetSize(argD) filter unextend(port(ffcemux, BA)) == argD.extract(0, GetSize(unextend(port(ffcemux, BA)))) // Remaining bits on argD must not have any other users @@ -374,24 +372,62 @@ match ffcemux semioptional endmatch -code argD ffmux +code argD argQ if (ffcemux) { dffcemux = ffcemux; dffcepol = ffcepol; argD = port(ffcemux, \Y); - ffmux = ffcemux; + argQ = port(ffcemux, ffcepol ? \A : \B); } else dffcemux = nullptr; endcode +match ffrstmux + if !argQ.empty() + select ffrstmux->type.in($mux) + // ffrstmux output must have two users: ffrstmux and ff.D + select nusers(port(ffrstmux, \Y)) == 2 + filter GetSize(port(ffrstmux, \Y)) >= GetSize(argD) + + choice BA {\B, \A} + // DSP48E1 only supports reset to zero + select port(ffrstmux, BA).is_fully_zero() + + define AB (BA == \B ? \A : \B) + // keep-last-value net must have exactly 2 users: ffrstmux, ffcemux/ + select nusers(port(ffrstmux, AB)) == 2 + + slice offset GetSize(port(ffrstmux, \Y)) + filter GetSize(port(ffrstmux, AB)) <= GetSize(argD) + filter port(ffrstmux, AB) == argD.extract(0, GetSize(port(ffrstmux, AB))) + // Remaining bits on argD must not have any other users + filter nusers(argD.extract_end(GetSize(port(ffrstmux, AB)))) <= 1 + + define pol (AB == \A) + set ffrstpol pol + semioptional +endmatch + +code argD argQ + if (ffrstmux) { + dffrstmux = ffrstmux; + dffrstpol = ffrstpol; + argD = port(ffrstmux, \Y); + } + else { + dffrstmux = nullptr; + argQ = SigSpec(); + } +endcode + match ff_enable - if ffmux + if !argQ.empty() select ff_enable->type.in($dff) // DSP48E1 does not support clock inversion select param(ff_enable, \CLK_POLARITY).as_bool() index port(ff_enable, \D) === argD - index port(ff_enable, \Q) === port(ffmux, ffcepol ? \A : \B) + index port(ff_enable, \Q) === argQ endmatch match ff @@ -421,7 +457,7 @@ code } dffclock = port(dff, \CLK); } - // No enable mux possible without flop - else if (ffmux) + // No enable/reset mux possible without flop + else if (ffcemux || ffrstmux) reject; endcode -- cgit v1.2.3 From 37a34eeb0438261f432917fb5d60a5320f56a8de Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 10 Sep 2019 20:56:13 -0700 Subject: Fix RSTP --- passes/pmgen/xilinx_dsp.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index fe82b1307..055b3d6aa 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -438,7 +438,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) st.ffPrstmux->connections_.at("\\Y").replace(P, pm.module->addWire(NEW_ID, GetSize(P))); } else - cell->setPort("\\RSTP", State::S1); + cell->setPort("\\RSTP", State::S0); if (st.ffPcemux) { SigSpec S = st.ffPcemux->getPort("\\S"); cell->setPort("\\CEP", st.ffPcepol ? S : pm.module->Not(NEW_ID, S)); -- cgit v1.2.3 From b08797da6bf0061073dc662441e03b2fd218f11f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 10 Sep 2019 21:33:14 -0700 Subject: Only pack out registers if \init is zero or x; then remove \init from PREG --- passes/pmgen/xilinx_dsp.cc | 10 ++++++++++ passes/pmgen/xilinx_dsp.pmg | 12 ++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 055b3d6aa..5d50c7795 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -451,6 +451,16 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) P.replace(pm.sigmap(D), Q); st.ffP->connections_.at("\\Q").replace(P, pm.module->addWire(NEW_ID, GetSize(P))); + for (auto c : Q.chunks()) { + auto it = c.wire->attributes.find("\\init"); + if (it == c.wire->attributes.end()) + continue; + for (int i = c.offset; i < c.offset+c.width; i++) { + log_assert(it->second[i] == State::S0 || it->second[i] == State::Sx); + it->second[i] = State::Sx; + } + } + cell->setParam("\\PREG", State::S1); } diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 05837d057..7db8e95a6 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -290,8 +290,8 @@ endmatch code argQ if (ff) { - for (auto b : argQ) - if (b.wire->get_bool_attribute(\keep)) + for (auto c : argQ.chunks()) + if (c.wire->get_bool_attribute(\keep)) reject; if (clock != SigBit()) { @@ -447,9 +447,13 @@ code if (dff) { dffQ = port(dff, \Q); - for (auto b : dffQ) - if (b.wire->get_bool_attribute(\keep)) + for (auto c : dffQ.chunks()) { + if (c.wire->get_bool_attribute(\keep)) reject; + Const init = c.wire->attributes.at(\init, State::Sx); + if (!init.is_fully_undef() && !init.is_fully_zero()) + reject; + } if (clock != SigBit()) { if (port(dff, \CLK) != clock) -- cgit v1.2.3 From edf90afd20046cb48273be8bc3da6ae2ea58d644 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 11 Sep 2019 00:56:38 -0700 Subject: Rename dffmuxext -> dffmux, also remove constants in dff+mux --- passes/pmgen/Makefile.inc | 2 +- passes/pmgen/peepopt.cc | 2 +- passes/pmgen/peepopt_dffmux.pmg | 89 ++++++++++++++++++++++++++++++++++++++ passes/pmgen/peepopt_dffmuxext.pmg | 55 ----------------------- 4 files changed, 91 insertions(+), 57 deletions(-) create mode 100644 passes/pmgen/peepopt_dffmux.pmg delete mode 100644 passes/pmgen/peepopt_dffmuxext.pmg (limited to 'passes') diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index 6648e2ec0..98691d0fe 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -27,7 +27,7 @@ $(eval $(call add_extra_objs,passes/pmgen/peepopt_pm.h)) PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul.pmg PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg -PEEPOPT_PATTERN += passes/pmgen/peepopt_dffmuxext.pmg +PEEPOPT_PATTERN += passes/pmgen/peepopt_dffmux.pmg passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN) $(P) mkdir -p passes/pmgen && python3 $< -o $@ -p peepopt $(filter-out $<,$^) diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index b57d26cef..72b02127a 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -60,7 +60,7 @@ struct PeepoptPass : public Pass { peepopt_pm pm(module, module->selected_cells()); pm.run_shiftmul(); pm.run_muldiv(); - pm.run_dffmuxext(); + pm.run_dffmux(); } } } diff --git a/passes/pmgen/peepopt_dffmux.pmg b/passes/pmgen/peepopt_dffmux.pmg new file mode 100644 index 000000000..4fc8e3b4c --- /dev/null +++ b/passes/pmgen/peepopt_dffmux.pmg @@ -0,0 +1,89 @@ +pattern dffmux + +state muxAB + +match dff + select dff->type == $dff + select GetSize(port(dff, \D)) > 1 +endmatch + +match mux + select mux->type == $mux + select GetSize(port(mux, \Y)) > 1 + choice AB {\A, \B} + //select port(mux, AB)[GetSize(port(mux, \Y))-1].wire + index port(mux, \Y) === port(dff, \D) + define BA (AB == \A ? \B : \A) + index port(mux, BA) === port(dff, \Q) + set muxAB AB +endmatch + +code + SigSpec &D = mux->connections_.at(muxAB); + SigSpec &Q = dff->connections_.at(\Q); + int width = GetSize(D); + + SigSpec AB = port(mux, muxAB); + if (AB[width-1] == AB[width-2]) { + did_something = true; + + SigBit sign = D[width-1]; + bool is_signed = sign.wire; + int i; + for (i = width-1; i >= 2; i--) { + if (!is_signed) { + module->connect(Q[i], sign); + if (D[i-1] != sign) + break; + } + else { + module->connect(Q[i], Q[i-1]); + if (D[i-2] != sign) + break; + } + } + + mux->connections_.at(\A).remove(i, width-i); + mux->connections_.at(\B).remove(i, width-i); + mux->connections_.at(\Y).remove(i, width-i); + mux->fixup_parameters(); + dff->connections_.at(\D).remove(i, width-i); + dff->connections_.at(\Q).remove(i, width-i); + dff->fixup_parameters(); + + log("dffmux pattern in %s: dff=%s, mux=%s; removed top %d bits.\n", log_id(module), log_id(dff), log_id(mux), width-i); + accept; + } + else { + int count = 0; + for (int i = width-1; i >= 0; i--) { + if (AB[i].wire) + continue; + Wire *w = Q[i].wire; + auto it = w->attributes.find(\init); + State init; + if (it != w->attributes.end()) + init = it->second[Q[i].offset]; + else + init = State::Sx; + + if (init == State::Sx || init == AB[i].data) { + count++; + module->connect(Q[i], AB[i]); + mux->connections_.at(\A).remove(i); + mux->connections_.at(\B).remove(i); + mux->connections_.at(\Y).remove(i); + dff->connections_.at(\D).remove(i); + dff->connections_.at(\Q).remove(i); + } + } + if (count > 0) { + did_something = true; + mux->fixup_parameters(); + dff->fixup_parameters(); + } + + log("dffmux pattern in %s: dff=%s, mux=%s; removed %d constant bits.\n", log_id(module), log_id(dff), log_id(mux), count); + accept; + } +endcode diff --git a/passes/pmgen/peepopt_dffmuxext.pmg b/passes/pmgen/peepopt_dffmuxext.pmg deleted file mode 100644 index 2465d6171..000000000 --- a/passes/pmgen/peepopt_dffmuxext.pmg +++ /dev/null @@ -1,55 +0,0 @@ -pattern dffmuxext - -state muxAB - -match dff - select dff->type == $dff - select GetSize(port(dff, \D)) > 1 -endmatch - -match mux - select mux->type == $mux - select GetSize(port(mux, \Y)) > 1 - choice AB {\A, \B} - //select port(mux, AB)[GetSize(port(mux, \Y))-1].wire - index port(mux, \Y) === port(dff, \D) - define BA (AB == \A ? \B : \A) - index port(mux, BA) === port(dff, \Q) - filter port(mux, AB)[GetSize(port(mux, \Y))-1] == port(mux, AB)[GetSize(port(mux, \Y))-2] - set muxAB AB -endmatch - -code - did_something = true; - - SigSpec &D = mux->connections_.at(muxAB); - SigSpec &Q = dff->connections_.at(\Q); - int width = GetSize(D); - - SigBit sign = D[width-1]; - bool is_signed = sign.wire; - int i; - for (i = width-1; i >= 2; i--) { - if (!is_signed) { - module->connect(Q[i], sign); - if (D[i-1] != sign) - break; - } - else { - module->connect(Q[i], Q[i-1]); - if (D[i-2] != sign) - break; - } - } - - mux->connections_.at(\A).remove(i, width-i); - mux->connections_.at(\B).remove(i, width-i); - mux->connections_.at(\Y).remove(i, width-i); - mux->fixup_parameters(); - dff->connections_.at(\D).remove(i, width-i); - dff->connections_.at(\Q).remove(i, width-i); - dff->fixup_parameters(); - - log("dffmuxext pattern in %s: dff=%s, mux=%s; removed top %d bits.\n", log_id(module), log_id(dff), log_id(mux), width-i); - accept; -endcode -- cgit v1.2.3 From c43e52d2d7d16c26b1a4a9c20fad83c9f4577910 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 11 Sep 2019 13:55:16 +0100 Subject: Add equiv_opt -multiclock Signed-off-by: David Shah --- passes/equiv/equiv_opt.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/equiv/equiv_opt.cc b/passes/equiv/equiv_opt.cc index 19d1c25ac..d4c7f7953 100644 --- a/passes/equiv/equiv_opt.cc +++ b/passes/equiv/equiv_opt.cc @@ -46,6 +46,9 @@ struct EquivOptPass:public ScriptPass log(" -assert\n"); log(" produce an error if the circuits are not equivalent.\n"); log("\n"); + log(" -multiclock\n"); + log(" run clk2fflogic before equivalence checking.\n"); + log("\n"); log(" -undef\n"); log(" enable modelling of undef states during equiv_induct.\n"); log("\n"); @@ -55,7 +58,7 @@ struct EquivOptPass:public ScriptPass } std::string command, techmap_opts; - bool assert, undef; + bool assert, undef, multiclock; void clear_flags() YS_OVERRIDE { @@ -63,6 +66,7 @@ struct EquivOptPass:public ScriptPass techmap_opts = ""; assert = false; undef = false; + multiclock = false; } void execute(std::vector < std::string > args, RTLIL::Design * design) YS_OVERRIDE @@ -92,6 +96,10 @@ struct EquivOptPass:public ScriptPass undef = true; continue; } + if (args[argidx] == "-multiclock") { + multiclock = true; + continue; + } break; } @@ -146,6 +154,8 @@ struct EquivOptPass:public ScriptPass } if (check_label("prove")) { + if (multiclock || help_mode) + run("clk2fflogic", "(only with -multiclock)"); run("equiv_make gold gate equiv"); if (help_mode) run("equiv_induct [-undef] equiv"); -- cgit v1.2.3 From ded805ae5d9d9884be319a710f159007e73c9636 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 11 Sep 2019 07:34:14 -0700 Subject: Add support for RSTM --- passes/pmgen/xilinx_dsp.cc | 31 ++++++--- passes/pmgen/xilinx_dsp.pmg | 152 +++++++++++++++++++++++++------------------- 2 files changed, 109 insertions(+), 74 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 5d50c7795..0700d3f61 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -269,7 +269,8 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("ffDmux: %s\n", log_id(st.ffDmux, "--")); log("dsp: %s\n", log_id(st.dsp, "--")); log("ffM: %s\n", log_id(st.ffM, "--")); - log("ffMmux: %s\n", log_id(st.ffMmux, "--")); + log("ffMcemux: %s\n", log_id(st.ffMcemux, "--")); + log("ffMrstmux: %s\n", log_id(st.ffMrstmux, "--")); log("postAdd: %s\n", log_id(st.postAdd, "--")); log("postAddMux: %s\n", log_id(st.postAddMux, "--")); log("ffP: %s\n", log_id(st.ffP, "--")); @@ -417,38 +418,48 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) cell->setParam("\\DREG", 1); } if (st.ffM) { - if (st.ffMmux) { - SigSpec S = st.ffMmux->getPort("\\S"); + if (st.ffMrstmux) { + SigSpec S = st.ffMrstmux->getPort("\\S"); + cell->setPort("\\RSTM", st.ffMrstpol ? S : pm.module->Not(NEW_ID, S)); + } + else + cell->setPort("\\RSTM", State::S0); + if (st.ffMcemux) { + SigSpec S = st.ffMcemux->getPort("\\S"); cell->setPort("\\CEM", st.ffMcepol ? S : pm.module->Not(NEW_ID, S)); - pm.autoremove(st.ffMmux); } else cell->setPort("\\CEM", State::S1); SigSpec D = st.ffM->getPort("\\D"); SigSpec Q = st.ffM->getPort("\\Q"); - P.replace(pm.sigmap(D), Q); + st.ffM->connections_.at("\\Q").replace(st.sigM, pm.module->addWire(NEW_ID, GetSize(st.sigM))); + + for (auto c : Q.chunks()) { + auto it = c.wire->attributes.find("\\init"); + if (it == c.wire->attributes.end()) + continue; + for (int i = c.offset; i < c.offset+c.width; i++) { + log_assert(it->second[i] == State::S0 || it->second[i] == State::Sx); + it->second[i] = State::Sx; + } + } cell->setParam("\\MREG", State::S1); - pm.autoremove(st.ffM); } if (st.ffP) { if (st.ffPrstmux) { SigSpec S = st.ffPrstmux->getPort("\\S"); cell->setPort("\\RSTP", st.ffPrstpol ? S : pm.module->Not(NEW_ID, S)); - st.ffPrstmux->connections_.at("\\Y").replace(P, pm.module->addWire(NEW_ID, GetSize(P))); } else cell->setPort("\\RSTP", State::S0); if (st.ffPcemux) { SigSpec S = st.ffPcemux->getPort("\\S"); cell->setPort("\\CEP", st.ffPcepol ? S : pm.module->Not(NEW_ID, S)); - st.ffPcemux->connections_.at("\\Y").replace(P, pm.module->addWire(NEW_ID, GetSize(P))); } else cell->setPort("\\CEP", State::S1); - SigSpec D = st.ffP->getPort("\\D"); SigSpec Q = st.ffP->getPort("\\Q"); - P.replace(pm.sigmap(D), Q); st.ffP->connections_.at("\\Q").replace(P, pm.module->addWire(NEW_ID, GetSize(P))); for (auto c : Q.chunks()) { diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 7db8e95a6..686efd8c4 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -4,14 +4,15 @@ state > unextend state clock state sigA sigffAmuxY sigB sigffBmuxY sigC sigffCmuxY sigD sigffDmuxY sigM sigP state postAddAB postAddMuxAB -state ffAcepol ffADcepol ffBcepol ffCcepol ffDcepol ffMcepol ffPcepol ffPrstpol +state ffAcepol ffADcepol ffBcepol ffCcepol ffDcepol ffMcepol ffMrstpol ffPcepol ffPrstpol state ffPoffset -state ffAD ffADmux ffA ffAmux ffB ffBmux ffC ffCmux ffD ffDmux ffM ffMmux ffP ffPcemux ffPrstmux +state ffAD ffADmux ffA ffAmux ffB ffBmux ffC ffCmux ffD ffDmux ffM ffMcemux ffMrstmux ffP ffPcemux ffPrstmux // subpattern state argQ argD state ffcepol ffrstpol +state ffoffset udata dffD dffQ udata dffclock udata dff dffcemux dffrstmux @@ -159,7 +160,7 @@ code argQ ffD ffDmux ffDcepol sigD clock } endcode -code argD ffM ffMmux ffMcepol sigM sigP clock +code argD ffM ffMcemux ffMrstmux ffMcepol ffMrstpol sigM sigP clock if (param(dsp, \MREG).as_int() == 0 && nusers(sigM) == 2) { argD = sigM; subpattern(out_dffe); @@ -167,8 +168,10 @@ code argD ffM ffMmux ffMcepol sigM sigP clock ffM = dff; clock = dffclock; if (dffcemux) { - ffMmux = dffcemux; + ffMcemux = dffcemux; + ffMrstmux = dffrstmux; ffMcepol = dffcepol; + ffMrstpol = dffrstpol; } sigM = dffQ; } @@ -185,8 +188,8 @@ match postAdd select nusers(port(postAdd, \Y)) == 2 choice AB {\A, \B} select nusers(port(postAdd, AB)) <= 3 - filter ffMmux || nusers(port(postAdd, AB)) == 2 - filter !ffMmux || nusers(port(postAdd, AB)) == 3 + filter ffMcemux || nusers(port(postAdd, AB)) == 2 + filter !ffMcemux || nusers(port(postAdd, AB)) == 3 filter GetSize(unextend(port(postAdd, AB))) <= GetSize(sigP) filter unextend(port(postAdd, AB)) == sigP.extract(0, GetSize(unextend(port(postAdd, AB)))) filter nusers(sigP.extract_end(GetSize(unextend(port(postAdd, AB))))) <= 1 @@ -214,10 +217,10 @@ endcode code argD ffP ffPcemux ffPrstmux ffPcepol ffPrstpol sigP clock if (param(dsp, \PREG).as_int() == 0) { - // If ffMmux and no postAdd new-value net must have exactly three users: ffMmux, ffM and ffPcemux - if ((ffMmux && !postAdd && nusers(sigP) == 3) || + // If ffMcemux and no postAdd new-value net must have exactly three users: ffMcemux, ffM and ffPcemux + if ((ffMcemux && !postAdd && nusers(sigP) == 3) || // Otherwise new-value net must have exactly two users: dsp and ffPcemux - ((!ffMmux || postAdd) && nusers(sigP) == 2)) { + ((!ffMcemux || postAdd) && nusers(sigP) == 2)) { argD = sigP; subpattern(out_dffe); if (dff) { @@ -347,107 +350,130 @@ subpattern out_dffe arg argD argQ clock arg unextend +code + dff = nullptr; +endcode + match ffcemux select ffcemux->type.in($mux) // ffcemux output must have two users: ffcemux and ff.D select nusers(port(ffcemux, \Y)) == 2 - filter GetSize(port(ffcemux, \Y)) >= GetSize(argD) - choice BA {\B, \A} - // new-value net must have exactly two users: (upstream) and ffcemux - select nusers(port(ffcemux, BA)) == 2 - - define AB (BA == \B ? \A : \B) + choice AB {\A, \B} // keep-last-value net must have at least three users: ffcemux, ff, downstream sink(s) select nusers(port(ffcemux, AB)) >= 3 slice offset GetSize(port(ffcemux, \Y)) - filter GetSize(unextend(port(ffcemux, BA))) <= GetSize(argD) - filter unextend(port(ffcemux, BA)) == argD.extract(0, GetSize(unextend(port(ffcemux, BA)))) - // Remaining bits on argD must not have any other users - filter nusers(argD.extract_end(GetSize(unextend(port(ffcemux, BA))))) <= 1 - - define pol (AB == \A) + define BA (AB == \A ? \B : \A) + index port(ffcemux, BA)[offset] === argD[0] + set ffoffset offset + define pol (BA == \B) set ffcepol pol + semioptional endmatch code argD argQ + dffcemux = ffcemux; if (ffcemux) { + SigSpec BA = port(ffcemux, ffcepol ? \B : \A); + if (ffoffset + GetSize(argD) > GetSize(BA)) + reject; + + for (int i = 1; i < GetSize(argD); i++) + if (BA[ffoffset+i] != argD[i]) + reject; + + SigSpec Y = port(ffcemux, \Y); + argQ = argD; + argD.replace(BA, Y); + argQ.replace(BA, port(ffcemux, ffcepol ? \A : \B)); + dffcemux = ffcemux; dffcepol = ffcepol; - argD = port(ffcemux, \Y); - argQ = port(ffcemux, ffcepol ? \A : \B); } - else - dffcemux = nullptr; endcode match ffrstmux - if !argQ.empty() select ffrstmux->type.in($mux) // ffrstmux output must have two users: ffrstmux and ff.D select nusers(port(ffrstmux, \Y)) == 2 - filter GetSize(port(ffrstmux, \Y)) >= GetSize(argD) choice BA {\B, \A} // DSP48E1 only supports reset to zero select port(ffrstmux, BA).is_fully_zero() - define AB (BA == \B ? \A : \B) - // keep-last-value net must have exactly 2 users: ffrstmux, ffcemux/ - select nusers(port(ffrstmux, AB)) == 2 - slice offset GetSize(port(ffrstmux, \Y)) - filter GetSize(port(ffrstmux, AB)) <= GetSize(argD) - filter port(ffrstmux, AB) == argD.extract(0, GetSize(port(ffrstmux, AB))) - // Remaining bits on argD must not have any other users - filter nusers(argD.extract_end(GetSize(port(ffrstmux, AB)))) <= 1 + define AB (BA == \B ? \A : \B) + index port(ffrstmux, AB)[offset] === argD[0] + filter !ffcemux || ffoffset == offset + set ffoffset offset define pol (AB == \A) set ffrstpol pol + semioptional endmatch code argD argQ + dffrstmux = ffrstmux; if (ffrstmux) { + SigSpec AB = port(ffrstmux, ffcepol ? \A : \B); + if (ffoffset + GetSize(argD) > GetSize(AB)) + reject; + + for (int i = 1; i < GetSize(argD); i++) + if (AB[ffoffset+i] != argD[i]) + reject; + + SigSpec Y = port(ffrstmux, \Y); + argD.replace(AB, Y); + dffrstmux = ffrstmux; dffrstpol = ffrstpol; - argD = port(ffrstmux, \Y); - } - else { - dffrstmux = nullptr; - argQ = SigSpec(); } endcode -match ff_enable - if !argQ.empty() - select ff_enable->type.in($dff) - // DSP48E1 does not support clock inversion - select param(ff_enable, \CLK_POLARITY).as_bool() - index port(ff_enable, \D) === argD - index port(ff_enable, \Q) === argQ -endmatch - match ff - if !ff_enable select ff->type.in($dff) // DSP48E1 does not support clock inversion select param(ff, \CLK_POLARITY).as_bool() - index port(ff, \D) === argD + + slice offset GetSize(port(ff, \D)) + index port(ff, \D)[offset] === argD[0] + + filter (!ffcemux && !ffrstmux) || ffoffset == offset + set ffoffset offset + semioptional endmatch -code - if (ff_enable) - dff = ff_enable; - else - dff = ff; - if (dff) { - dffQ = port(dff, \Q); +code argQ + if (ff) { + if (clock != SigBit()) { + if (port(ff, \CLK) != clock) + reject; + } - for (auto c : dffQ.chunks()) { + SigSpec D = port(ff, \D); + if (ffoffset + GetSize(argD) > GetSize(D)) + reject; + for (int i = 1; i < GetSize(argD); i++) + if (D[ffoffset+i] != argD[i]) + reject; + + SigSpec Q = port(ff, \Q); + if (ffcemux) { + for (int i = 0; i < GetSize(argQ); i++) + if (Q[ffoffset+i] != argQ[i]) + reject; + } + else { + argQ = argD; + argQ.replace(D, Q); + } + + for (auto c : argQ.chunks()) { if (c.wire->get_bool_attribute(\keep)) reject; Const init = c.wire->attributes.at(\init, State::Sx); @@ -455,13 +481,11 @@ code reject; } - if (clock != SigBit()) { - if (port(dff, \CLK) != clock) - reject; - } + dff = ff; + dffQ = argQ; dffclock = port(dff, \CLK); } // No enable/reset mux possible without flop - else if (ffcemux || ffrstmux) + else if (dffcemux || dffrstmux) reject; endcode -- cgit v1.2.3 From 0d709d2bb56fed3a1100b72071ca8d584746a095 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 11 Sep 2019 10:15:19 -0700 Subject: Add support for A/B/C/D/AD reset --- passes/pmgen/xilinx_dsp.cc | 121 +++++++++++---------------------- passes/pmgen/xilinx_dsp.pmg | 159 ++++++++++++++++++++++++++++---------------- 2 files changed, 141 insertions(+), 139 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 0700d3f61..fdd0ac2fa 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -257,25 +257,16 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) #if 1 log("\n"); log("preAdd: %s\n", log_id(st.preAdd, "--")); - log("ffAD: %s\n", log_id(st.ffAD, "--")); - log("ffADmux: %s\n", log_id(st.ffADmux, "--")); - log("ffA: %s\n", log_id(st.ffA, "--")); - log("ffAmux: %s\n", log_id(st.ffAmux, "--")); - log("ffB: %s\n", log_id(st.ffB, "--")); - log("ffBmux: %s\n", log_id(st.ffBmux, "--")); - log("ffC: %s\n", log_id(st.ffC, "--")); - log("ffCmux: %s\n", log_id(st.ffCmux, "--")); - log("ffD: %s\n", log_id(st.ffD, "--")); - log("ffDmux: %s\n", log_id(st.ffDmux, "--")); + log("ffAD: %s %s %s\n", log_id(st.ffAD, "--"), log_id(st.ffADcemux, "--"), log_id(st.ffADrstmux, "--")); + log("ffA: %s %s %s\n", log_id(st.ffA, "--"), log_id(st.ffAcemux, "--"), log_id(st.ffArstmux, "--")); + log("ffB: %s %s %s\n", log_id(st.ffB, "--"), log_id(st.ffBcemux, "--"), log_id(st.ffBrstmux, "--")); + log("ffC: %s %s %s\n", log_id(st.ffC, "--"), log_id(st.ffCcemux, "--"), log_id(st.ffCrstmux, "--")); + log("ffD: %s %s %s\n", log_id(st.ffD, "--"), log_id(st.ffDcemux, "--"), log_id(st.ffDrstmux, "--")); log("dsp: %s\n", log_id(st.dsp, "--")); - log("ffM: %s\n", log_id(st.ffM, "--")); - log("ffMcemux: %s\n", log_id(st.ffMcemux, "--")); - log("ffMrstmux: %s\n", log_id(st.ffMrstmux, "--")); + log("ffM: %s %s %s\n", log_id(st.ffM, "--"), log_id(st.ffMcemux, "--"), log_id(st.ffMrstmux, "--")); log("postAdd: %s\n", log_id(st.postAdd, "--")); log("postAddMux: %s\n", log_id(st.postAddMux, "--")); - log("ffP: %s\n", log_id(st.ffP, "--")); - log("ffPcemux: %s\n", log_id(st.ffPcemux, "--")); - log("ffPrstmux: %s\n", log_id(st.ffPrstmux, "--")); + log("ffP: %s %s %s\n", log_id(st.ffP, "--"), log_id(st.ffPcemux, "--"), log_id(st.ffPrstmux, "--")); #endif log("Analysing %s.%s for Xilinx DSP packing.\n", log_id(pm.module), log_id(st.dsp)); @@ -297,8 +288,8 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) cell->connections_.at("\\INMODE") = Const::from_string("00100"); if (st.ffAD) { - if (st.ffADmux) { - SigSpec S = st.ffADmux->getPort("\\S"); + if (st.ffADcemux) { + SigSpec S = st.ffADcemux->getPort("\\S"); cell->setPort("\\CEAD", st.ffADcepol ? S : pm.module->Not(NEW_ID, S)); } else @@ -341,80 +332,46 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) { cell->setPort("\\CLK", st.clock); - if (st.ffA) { - SigSpec A = cell->getPort("\\A"); - SigSpec D = st.ffA->getPort("\\D"); - SigSpec Q = pm.sigmap(st.ffA->getPort("\\Q")); + auto f = [&pm,cell](IdString port, Cell* ff, Cell* cemux, bool cepol, IdString ceport, Cell* rstmux, bool rstpol, IdString rstport) { + SigSpec A = cell->getPort(port); + SigSpec D = ff->getPort("\\D"); + SigSpec Q = pm.sigmap(ff->getPort("\\Q")); A.replace(Q, D); - if (st.ffAmux) { - SigSpec Y = st.ffAmux->getPort("\\Y"); - SigSpec AB = st.ffAmux->getPort(st.ffAcepol ? "\\B" : "\\A"); - SigSpec S = st.ffAmux->getPort("\\S"); + if (rstmux) { + SigSpec Y = rstmux->getPort("\\Y"); + SigSpec AB = rstmux->getPort(rstpol ? "\\A" : "\\B"); + SigSpec S = rstmux->getPort("\\S"); A.replace(Y, AB); - cell->setPort("\\CEA2", st.ffAcepol ? S : pm.module->Not(NEW_ID, S)); + cell->setPort(rstport, rstpol ? S : pm.module->Not(NEW_ID, S)); + } + else + cell->setPort(rstport, State::S0); + if (cemux) { + SigSpec Y = cemux->getPort("\\Y"); + SigSpec BA = cemux->getPort(cepol ? "\\B" : "\\A"); + SigSpec S = cemux->getPort("\\S"); + A.replace(Y, BA); + cell->setPort(ceport, cepol ? S : pm.module->Not(NEW_ID, S)); } else - cell->setPort("\\CEA2", State::S1); - cell->setPort("\\A", A); + cell->setPort(ceport, State::S1); + cell->setPort(port, A); + }; + if (st.ffA) { + f("\\A", st.ffA, st.ffAcemux, st.ffAcepol, "\\CEA2", st.ffArstmux, st.ffArstpol, "\\RSTA"); cell->setParam("\\AREG", 1); } if (st.ffB) { - SigSpec B = cell->getPort("\\B"); - SigSpec D = st.ffB->getPort("\\D"); - SigSpec Q = st.ffB->getPort("\\Q"); - B.replace(Q, D); - if (st.ffBmux) { - SigSpec Y = st.ffBmux->getPort("\\Y"); - SigSpec AB = st.ffBmux->getPort(st.ffBcepol ? "\\B" : "\\A"); - SigSpec S = st.ffBmux->getPort("\\S"); - B.replace(Y, AB); - cell->setPort("\\CEB2", st.ffBcepol ? S : pm.module->Not(NEW_ID, S)); - } - else - cell->setPort("\\CEB2", State::S1); - cell->setPort("\\B", B); - + f("\\B", st.ffB, st.ffBcemux, st.ffBcepol, "\\CEB2", st.ffBrstmux, st.ffBrstpol, "\\RSTB"); cell->setParam("\\BREG", 1); } if (st.ffC) { - SigSpec C = cell->getPort("\\C"); - SigSpec D = st.ffC->getPort("\\D"); - SigSpec Q = st.ffC->getPort("\\Q"); - C.replace(Q, D); - - if (st.ffCmux) { - SigSpec Y = st.ffCmux->getPort("\\Y"); - SigSpec AB = st.ffCmux->getPort(st.ffCcepol ? "\\B" : "\\A"); - SigSpec S = st.ffCmux->getPort("\\S"); - C.replace(Y, AB); - - cell->setPort("\\CEC", st.ffCcepol ? S : pm.module->Not(NEW_ID, S)); - } - else - cell->setPort("\\CEC", State::S1); - cell->setPort("\\C", C); - + f("\\C", st.ffC, st.ffCcemux, st.ffCcepol, "\\CEC", st.ffCrstmux, st.ffCrstpol, "\\RSTC"); cell->setParam("\\CREG", 1); } if (st.ffD) { - SigSpec D_ = cell->getPort("\\D"); - SigSpec D = st.ffD->getPort("\\D"); - SigSpec Q = st.ffD->getPort("\\Q"); - D_.replace(Q, D); - - if (st.ffDmux) { - SigSpec Y = st.ffDmux->getPort("\\Y"); - SigSpec AB = st.ffDmux->getPort(st.ffDcepol ? "\\B" : "\\A"); - SigSpec S = st.ffDmux->getPort("\\S"); - D_.replace(Y, AB); - - cell->setPort("\\CED", st.ffDcepol ? S : pm.module->Not(NEW_ID, S)); - } - else - cell->setPort("\\CED", State::S1); - cell->setPort("\\D", D_); - + f("\\D", st.ffD, st.ffDcemux, st.ffDcepol, "\\CED", st.ffDrstmux, st.ffDrstpol, "\\RSTD"); cell->setParam("\\DREG", 1); } if (st.ffM) { @@ -516,9 +473,9 @@ struct XilinxDspPass : public Pass { log("\n"); log(" xilinx_dsp [options] [selection]\n"); log("\n"); - log("Pack input registers (A, B, C, D, AD; with optional enable), pipeline registers\n"); - log("(M; with optional enable), output registers (P; with optional enable),\n"); - log("pre-adder and/or post-adder into Xilinx DSP resources.\n"); + log("Pack input registers (A, B, C, D, AD; with optional enable/reset), pipeline\n"); + log("registers (M; with optional enable/reset), output registers (P; with optional\n"); + log("enable/reset), pre-adder and/or post-adder into Xilinx DSP resources.\n"); log("\n"); log("Multiply-accumulate operations using the post-adder with feedback on the 'C'\n"); log("input will be folded into the DSP. In this scenario only, the 'C' input can be\n"); @@ -528,8 +485,6 @@ struct XilinxDspPass : public Pass { log("where 'P' is right-shifted by 18-bits and used as an input to the post-adder (a\n"); log("pattern common for summing partial products to implement wide multiplies).\n"); log("\n"); - log("Not currently supported: reset (RST*) inputs on any register.\n"); - log("\n"); log("\n"); log("Experimental feature: addition/subtractions less than 12 or 24 bits with the\n"); log("'(* use_dsp=\"simd\" *)' attribute attached to the output wire or attached to\n"); diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 686efd8c4..6e726d1c2 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -2,12 +2,13 @@ pattern xilinx_dsp state > unextend state clock -state sigA sigffAmuxY sigB sigffBmuxY sigC sigffCmuxY sigD sigffDmuxY sigM sigP +state sigA sigffAcemuxY sigB sigffBcemuxY sigC sigffCcemuxY sigD sigffDcemuxY sigM sigP state postAddAB postAddMuxAB -state ffAcepol ffADcepol ffBcepol ffCcepol ffDcepol ffMcepol ffMrstpol ffPcepol ffPrstpol -state ffPoffset +state ffAcepol ffADcepol ffBcepol ffCcepol ffDcepol ffMcepol ffPcepol +state ffArstpol ffADrstpol ffBrstpol ffCrstpol ffDrstpol ffMrstpol ffPrstpol -state ffAD ffADmux ffA ffAmux ffB ffBmux ffC ffCmux ffD ffDmux ffM ffMcemux ffMrstmux ffP ffPcemux ffPrstmux +state ffAD ffADcemux ffADrstmux ffA ffAcemux ffArstmux ffB ffBcemux ffBrstmux ffC ffCcemux ffCrstmux +state ffD ffDcemux ffDrstmux ffM ffMcemux ffMrstmux ffP ffPcemux ffPrstmux // subpattern state argQ argD @@ -54,7 +55,7 @@ code unextend sigA sigB sigC sigD sigM sigM = P; endcode -code argQ ffAD ffADmux ffADcepol sigA clock +code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock if (param(dsp, \ADREG).as_int() == 0) { argQ = sigA; subpattern(in_dffe); @@ -62,8 +63,10 @@ code argQ ffAD ffADmux ffADcepol sigA clock ffAD = dff; clock = dffclock; if (dffcemux) { - ffADmux = dffcemux; + ffADcemux = dffcemux; + ffADrstmux = dffrstmux; ffADcepol = dffcepol; + ffADrstpol = dffrstpol; } sigA = dffD; } @@ -100,7 +103,7 @@ code sigA sigD } endcode -code argQ ffA ffAmux ffAcepol sigA clock ffAD ffADmux ffADcepol +code argQ ffA ffAcemux ffArstmux ffAcepol ffArstpol sigA clock ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol // Only search for ffA if there was a pre-adder // (otherwise ffA would have been matched as ffAD) if (preAdd) { @@ -111,8 +114,10 @@ code argQ ffA ffAmux ffAcepol sigA clock ffAD ffADmux ffADcepol ffA = dff; clock = dffclock; if (dffcemux) { - ffAmux = dffcemux; + ffAcemux = dffcemux; + ffArstmux = dffrstmux; ffAcepol = dffcepol; + ffArstpol = dffrstpol; } sigA = dffD; } @@ -121,14 +126,16 @@ code argQ ffA ffAmux ffAcepol sigA clock ffAD ffADmux ffADcepol // And if there wasn't a pre-adder, // move AD register to A else if (ffAD) { - log_assert(!ffA && !ffAmux); + log_assert(!ffA && !ffAcemux && !ffArstmux); std::swap(ffA, ffAD); - std::swap(ffAmux, ffADmux); + std::swap(ffAcemux, ffADcemux); + std::swap(ffArstmux, ffADrstmux); ffAcepol = ffADcepol; + ffArstpol = ffADrstpol; } endcode -code argQ ffB ffBmux ffBcepol sigB clock +code argQ ffB ffBcemux ffBrstmux ffBcepol ffBrstpol sigB clock if (param(dsp, \BREG).as_int() == 0) { argQ = sigB; subpattern(in_dffe); @@ -136,15 +143,17 @@ code argQ ffB ffBmux ffBcepol sigB clock ffB = dff; clock = dffclock; if (dffcemux) { - ffBmux = dffcemux; + ffBcemux = dffcemux; + ffBrstmux = dffrstmux; ffBcepol = dffcepol; + ffBrstpol = dffrstpol; } sigB = dffD; } } endcode -code argQ ffD ffDmux ffDcepol sigD clock +code argQ ffD ffDcemux ffDrstmux ffDcepol ffDrstpol sigD clock if (param(dsp, \DREG).as_int() == 0) { argQ = sigD; subpattern(in_dffe); @@ -152,8 +161,10 @@ code argQ ffD ffDmux ffDcepol sigD clock ffD = dff; clock = dffclock; if (dffcemux) { - ffDmux = dffcemux; + ffDcemux = dffcemux; + ffDrstmux = dffrstmux; ffDcepol = dffcepol; + ffDrstpol = dffrstpol; } sigD = dffD; } @@ -255,16 +266,18 @@ code sigC sigC = port(postAddMux, postAddMuxAB == \A ? \B : \A); endcode -code argQ ffC ffCmux ffCcepol sigC clock - if (param(dsp, \CREG).as_int() == 0) { +code argQ ffC ffCcemux ffCrstmux ffCcepol ffCrstpol sigC clock + if (param(dsp, \CREG).as_int() == 0 && sigC != sigP) { argQ = sigC; subpattern(in_dffe); if (dff) { ffC = dff; clock = dffclock; if (dffcemux) { - ffCmux = dffcemux; + ffCcemux = dffcemux; + ffCrstmux = dffrstmux; ffCcepol = dffcepol; + ffCrstpol = dffrstpol; } sigC = dffD; } @@ -278,67 +291,102 @@ endcode // ####################### subpattern in_dffe -arg argQ clock ffcepol +arg argD argQ clock + +code + dff = nullptr; + for (auto c : argQ.chunks()) { + if (!c.wire) + reject; + if (c.wire->get_bool_attribute(\keep)) + reject; + } +endcode match ff select ff->type.in($dff) // DSP48E1 does not support clock inversion select param(ff, \CLK_POLARITY).as_bool() - filter GetSize(port(ff, \Q)) >= GetSize(argQ) - slice offset GetSize(port(ff, \Q)) - filter offset+GetSize(argQ) <= GetSize(port(ff, \Q)) - filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ - semioptional + + slice offset GetSize(port(ff, \D)) + index port(ff, \Q)[offset] === argQ[0] + set ffoffset offset endmatch -code argQ - if (ff) { - for (auto c : argQ.chunks()) - if (c.wire->get_bool_attribute(\keep)) - reject; +code argQ argD +{ + if (clock != SigBit()) { + if (port(ff, \CLK) != clock) + reject; + } - if (clock != SigBit()) { - if (port(ff, \CLK) != clock) - reject; - } - dffclock = port(ff, \CLK); + SigSpec Q = port(ff, \Q); + if (ffoffset + GetSize(argQ) > GetSize(Q)) + reject; + for (int i = 1; i < GetSize(argQ); i++) + if (Q[ffoffset+i] != argQ[i]) + reject; - dff = ff; - dffD = argQ; - dffD.replace(port(ff, \Q), port(ff, \D)); - // Only search for ffcemux if argQ has at - // least 3 users (ff, , ffcemux) and - // its ff.D only has two (ff, ffcemux) + dff = ff; + dffclock = port(ff, \CLK); + dffD = argQ; + argD = port(ff, \D); + argQ = Q; + dffD.replace(argQ, argD); + // Only search for ffrstmux if dffD only + // has two (ff, ffrstmux) users + if (nusers(dffD) > 2) + argD = SigSpec(); +} +endcode + +match ffrstmux + if !argD.empty() + select ffrstmux->type.in($mux) + index port(ffrstmux, \Y) === argD + + choice BA {\B, \A} + // DSP48E1 only supports reset to zero + select port(ffrstmux, BA).is_fully_zero() + + define pol (BA == \B) + set ffrstpol pol + semioptional +endmatch + +code argD + if (ffrstmux) { + dffrstmux = ffrstmux; + dffrstpol = ffrstpol; + argD = port(ffrstmux, ffrstpol ? \A : \B); + dffD.replace(port(ffrstmux, \Y), argD); + + // Only search for ffrstmux if argQ has at + // least 3 users (ff, , ffrstmux) and + // dffD only has two (ff, ffrstmux) if (!(nusers(argQ) >= 3 && nusers(dffD) == 2)) - argQ = SigSpec(); - } - else { - dff = nullptr; - argQ = SigSpec(); + argD = SigSpec(); } + else + dffrstmux = nullptr; endcode match ffcemux - if !argQ.empty() + if !argD.empty() select ffcemux->type.in($mux) - index port(ffcemux, \Y) === port(ff, \D) - filter GetSize(port(ffcemux, \Y)) >= GetSize(dffD) - slice offset GetSize(port(ffcemux, \Y)) - filter offset+GetSize(dffD) <= GetSize(port(ffcemux, \Y)) - filter port(ffcemux, \Y).extract(offset, GetSize(dffD)) == dffD + index port(ffcemux, \Y) === argD choice AB {\A, \B} - filter offset+GetSize(argQ) <= GetSize(port(ffcemux, \Y)) - filter port(ffcemux, AB).extract(offset, GetSize(argQ)) == argQ + index port(ffcemux, AB) === argQ define pol (AB == \A) set ffcepol pol semioptional endmatch -code +code argD if (ffcemux) { dffcemux = ffcemux; dffcepol = ffcepol; - dffD = port(ffcemux, dffcepol ? \B : \A); + dffD.replace(port(ffcemux, \Y), argD); } else dffcemux = nullptr; @@ -379,7 +427,6 @@ code argD argQ SigSpec BA = port(ffcemux, ffcepol ? \B : \A); if (ffoffset + GetSize(argD) > GetSize(BA)) reject; - for (int i = 1; i < GetSize(argD); i++) if (BA[ffoffset+i] != argD[i]) reject; @@ -440,7 +487,7 @@ match ff select param(ff, \CLK_POLARITY).as_bool() slice offset GetSize(port(ff, \D)) - index port(ff, \D)[offset] === argD[0] + index port(ff, \D)[offset] === argD[0] filter (!ffcemux && !ffrstmux) || ffoffset == offset set ffoffset offset -- cgit v1.2.3 From f72765090cd001ff4dc54d5a9c01a2d4b3339865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Tue, 10 Sep 2019 16:31:50 +0000 Subject: Add -match-init option to dff2dffs. --- passes/techmap/dff2dffs.cc | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/techmap/dff2dffs.cc b/passes/techmap/dff2dffs.cc index 0ea033513..3fa1ed5cf 100644 --- a/passes/techmap/dff2dffs.cc +++ b/passes/techmap/dff2dffs.cc @@ -34,11 +34,16 @@ struct Dff2dffsPass : public Pass { log("Merge synchronous set/reset $_MUX_ cells to create $__DFFS_[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 args, RTLIL::Design *design) YS_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++) { @@ -46,6 +51,10 @@ struct Dff2dffsPass : public Pass { // singleton_mode = true; // continue; // } + if (args[argidx] == "-match-init") { + match_init = true; + continue; + } break; } extra_args(args, argidx, design); @@ -96,9 +105,6 @@ struct Dff2dffsPass : public Pass { SigBit bit_b = sigmap(mux_cell->getPort(ID::B)); SigBit bit_s = sigmap(mux_cell->getPort(ID(S))); - 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)); - SigBit sr_val, sr_sig; bool invert_sr; sr_sig = bit_s; @@ -113,6 +119,23 @@ struct Dff2dffsPass : public Pass { 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($__DFFS_NN1_); -- cgit v1.2.3 From e5bdb521fa5ca535ef51d080f11d3470003b49e2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 11 Sep 2019 10:55:45 -0700 Subject: More cleanup --- passes/pmgen/xilinx_dsp.cc | 90 +++++++++++++++------------------------------- 1 file changed, 28 insertions(+), 62 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index fdd0ac2fa..f28b729dd 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -273,7 +273,6 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) Cell *cell = st.dsp; bit_to_driver.insert(std::make_pair(cell->getPort("\\P")[17], cell)); - SigSpec P = st.sigP; if (st.preAdd) { log(" preadder %s (%s)\n", log_id(st.preAdd), log_id(st.preAdd->type)); @@ -310,7 +309,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) opmode[4] = st.postAddMux->getPort("\\S"); pm.autoremove(st.postAddMux); } - else if (st.ffP && st.sigC == P) + else if (st.ffP && st.sigC == st.sigP) opmode[4] = State::S0; else opmode[4] = State::S1; @@ -332,16 +331,17 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) { cell->setPort("\\CLK", st.clock); - auto f = [&pm,cell](IdString port, Cell* ff, Cell* cemux, bool cepol, IdString ceport, Cell* rstmux, bool rstpol, IdString rstport) { - SigSpec A = cell->getPort(port); + auto f = [&pm,cell](SigSpec &A, Cell* ff, Cell* cemux, bool cepol, IdString ceport, Cell* rstmux, bool rstpol, IdString rstport) { SigSpec D = ff->getPort("\\D"); SigSpec Q = pm.sigmap(ff->getPort("\\Q")); - A.replace(Q, D); + if (!A.empty()) + A.replace(Q, D); if (rstmux) { SigSpec Y = rstmux->getPort("\\Y"); SigSpec AB = rstmux->getPort(rstpol ? "\\A" : "\\B"); SigSpec S = rstmux->getPort("\\S"); - A.replace(Y, AB); + if (!A.empty()) + A.replace(Y, AB); cell->setPort(rstport, rstpol ? S : pm.module->Not(NEW_ID, S)); } else @@ -350,85 +350,50 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) SigSpec Y = cemux->getPort("\\Y"); SigSpec BA = cemux->getPort(cepol ? "\\B" : "\\A"); SigSpec S = cemux->getPort("\\S"); - A.replace(Y, BA); + if (!A.empty()) + A.replace(Y, BA); cell->setPort(ceport, cepol ? S : pm.module->Not(NEW_ID, S)); } else cell->setPort(ceport, State::S1); - cell->setPort(port, A); + + for (auto c : Q.chunks()) { + auto it = c.wire->attributes.find("\\init"); + if (it == c.wire->attributes.end()) + continue; + for (int i = c.offset; i < c.offset+c.width; i++) { + log_assert(it->second[i] == State::S0 || it->second[i] == State::Sx); + it->second[i] = State::Sx; + } + } }; if (st.ffA) { - f("\\A", st.ffA, st.ffAcemux, st.ffAcepol, "\\CEA2", st.ffArstmux, st.ffArstpol, "\\RSTA"); + f(cell->connections_.at("\\A"), st.ffA, st.ffAcemux, st.ffAcepol, "\\CEA2", st.ffArstmux, st.ffArstpol, "\\RSTA"); cell->setParam("\\AREG", 1); } if (st.ffB) { - f("\\B", st.ffB, st.ffBcemux, st.ffBcepol, "\\CEB2", st.ffBrstmux, st.ffBrstpol, "\\RSTB"); + f(cell->connections_.at("\\B"), st.ffB, st.ffBcemux, st.ffBcepol, "\\CEB2", st.ffBrstmux, st.ffBrstpol, "\\RSTB"); cell->setParam("\\BREG", 1); } if (st.ffC) { - f("\\C", st.ffC, st.ffCcemux, st.ffCcepol, "\\CEC", st.ffCrstmux, st.ffCrstpol, "\\RSTC"); + f(cell->connections_.at("\\C"), st.ffC, st.ffCcemux, st.ffCcepol, "\\CEC", st.ffCrstmux, st.ffCrstpol, "\\RSTC"); cell->setParam("\\CREG", 1); } if (st.ffD) { - f("\\D", st.ffD, st.ffDcemux, st.ffDcepol, "\\CED", st.ffDrstmux, st.ffDrstpol, "\\RSTD"); + f(cell->connections_.at("\\D"), st.ffD, st.ffDcemux, st.ffDcepol, "\\CED", st.ffDrstmux, st.ffDrstpol, "\\RSTD"); cell->setParam("\\DREG", 1); } if (st.ffM) { - if (st.ffMrstmux) { - SigSpec S = st.ffMrstmux->getPort("\\S"); - cell->setPort("\\RSTM", st.ffMrstpol ? S : pm.module->Not(NEW_ID, S)); - } - else - cell->setPort("\\RSTM", State::S0); - if (st.ffMcemux) { - SigSpec S = st.ffMcemux->getPort("\\S"); - cell->setPort("\\CEM", st.ffMcepol ? S : pm.module->Not(NEW_ID, S)); - } - else - cell->setPort("\\CEM", State::S1); - SigSpec D = st.ffM->getPort("\\D"); - SigSpec Q = st.ffM->getPort("\\Q"); + SigSpec _; + f(_, st.ffM, st.ffMcemux, st.ffMcepol, "\\CEM", st.ffMrstmux, st.ffMrstpol, "\\RSTM"); st.ffM->connections_.at("\\Q").replace(st.sigM, pm.module->addWire(NEW_ID, GetSize(st.sigM))); - - for (auto c : Q.chunks()) { - auto it = c.wire->attributes.find("\\init"); - if (it == c.wire->attributes.end()) - continue; - for (int i = c.offset; i < c.offset+c.width; i++) { - log_assert(it->second[i] == State::S0 || it->second[i] == State::Sx); - it->second[i] = State::Sx; - } - } - cell->setParam("\\MREG", State::S1); } if (st.ffP) { - if (st.ffPrstmux) { - SigSpec S = st.ffPrstmux->getPort("\\S"); - cell->setPort("\\RSTP", st.ffPrstpol ? S : pm.module->Not(NEW_ID, S)); - } - else - cell->setPort("\\RSTP", State::S0); - if (st.ffPcemux) { - SigSpec S = st.ffPcemux->getPort("\\S"); - cell->setPort("\\CEP", st.ffPcepol ? S : pm.module->Not(NEW_ID, S)); - } - else - cell->setPort("\\CEP", State::S1); - SigSpec Q = st.ffP->getPort("\\Q"); - st.ffP->connections_.at("\\Q").replace(P, pm.module->addWire(NEW_ID, GetSize(P))); - - for (auto c : Q.chunks()) { - auto it = c.wire->attributes.find("\\init"); - if (it == c.wire->attributes.end()) - continue; - for (int i = c.offset; i < c.offset+c.width; i++) { - log_assert(it->second[i] == State::S0 || it->second[i] == State::Sx); - it->second[i] = State::Sx; - } - } - + SigSpec _; + f(_, st.ffP, st.ffPcemux, st.ffPcepol, "\\CEP", st.ffPrstmux, st.ffPrstpol, "\\RSTP"); + st.ffP->connections_.at("\\Q").replace(st.sigP, pm.module->addWire(NEW_ID, GetSize(st.sigP))); cell->setParam("\\PREG", State::S1); } @@ -458,6 +423,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("\n"); } + SigSpec P = st.sigP; if (GetSize(P) < 48) P.append(pm.module->addWire(NEW_ID, 48-GetSize(P))); cell->setPort("\\P", P); -- cgit v1.2.3 From d232e6a6cd8ed0ac0e76a1e6b787cb6dead855f0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 11 Sep 2019 11:46:21 -0700 Subject: Input registers to add DSP as new siguser to block upstream packing --- passes/pmgen/xilinx_dsp.cc | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index f28b729dd..d9d1bfea4 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -369,30 +369,38 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) }; if (st.ffA) { - f(cell->connections_.at("\\A"), st.ffA, st.ffAcemux, st.ffAcepol, "\\CEA2", st.ffArstmux, st.ffArstpol, "\\RSTA"); + SigSpec &A = cell->connections_.at("\\A"); + f(A, st.ffA, st.ffAcemux, st.ffAcepol, "\\CEA2", st.ffArstmux, st.ffArstpol, "\\RSTA"); + pm.add_siguser(A, cell); cell->setParam("\\AREG", 1); } if (st.ffB) { - f(cell->connections_.at("\\B"), st.ffB, st.ffBcemux, st.ffBcepol, "\\CEB2", st.ffBrstmux, st.ffBrstpol, "\\RSTB"); + SigSpec &B = cell->connections_.at("\\B"); + f(B, st.ffB, st.ffBcemux, st.ffBcepol, "\\CEB2", st.ffBrstmux, st.ffBrstpol, "\\RSTB"); + pm.add_siguser(B, cell); cell->setParam("\\BREG", 1); } if (st.ffC) { - f(cell->connections_.at("\\C"), st.ffC, st.ffCcemux, st.ffCcepol, "\\CEC", st.ffCrstmux, st.ffCrstpol, "\\RSTC"); + SigSpec &C = cell->connections_.at("\\C"); + f(C, st.ffC, st.ffCcemux, st.ffCcepol, "\\CEC", st.ffCrstmux, st.ffCrstpol, "\\RSTC"); + pm.add_siguser(C, cell); cell->setParam("\\CREG", 1); } if (st.ffD) { - f(cell->connections_.at("\\D"), st.ffD, st.ffDcemux, st.ffDcepol, "\\CED", st.ffDrstmux, st.ffDrstpol, "\\RSTD"); + SigSpec &D = cell->connections_.at("\\D"); + f(D, st.ffD, st.ffDcemux, st.ffDcepol, "\\CED", st.ffDrstmux, st.ffDrstpol, "\\RSTD"); + pm.add_siguser(D, cell); cell->setParam("\\DREG", 1); } if (st.ffM) { - SigSpec _; - f(_, st.ffM, st.ffMcemux, st.ffMcepol, "\\CEM", st.ffMrstmux, st.ffMrstpol, "\\RSTM"); + SigSpec M; // unused + f(M, st.ffM, st.ffMcemux, st.ffMcepol, "\\CEM", st.ffMrstmux, st.ffMrstpol, "\\RSTM"); st.ffM->connections_.at("\\Q").replace(st.sigM, pm.module->addWire(NEW_ID, GetSize(st.sigM))); cell->setParam("\\MREG", State::S1); } if (st.ffP) { - SigSpec _; - f(_, st.ffP, st.ffPcemux, st.ffPcepol, "\\CEP", st.ffPrstmux, st.ffPrstpol, "\\RSTP"); + SigSpec P; // unused + f(P, st.ffP, st.ffPcemux, st.ffPcepol, "\\CEP", st.ffPrstmux, st.ffPrstpol, "\\RSTP"); st.ffP->connections_.at("\\Q").replace(st.sigP, pm.module->addWire(NEW_ID, GetSize(st.sigP))); cell->setParam("\\PREG", State::S1); } -- cgit v1.2.3 From bbef0d2ac8a84299109d9bd93b5eb69a5500d594 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 11 Sep 2019 12:29:26 -0700 Subject: Only display log message if did_something --- passes/pmgen/peepopt_dffmux.pmg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/peepopt_dffmux.pmg b/passes/pmgen/peepopt_dffmux.pmg index 4fc8e3b4c..da3a66577 100644 --- a/passes/pmgen/peepopt_dffmux.pmg +++ b/passes/pmgen/peepopt_dffmux.pmg @@ -81,9 +81,9 @@ code did_something = true; mux->fixup_parameters(); dff->fixup_parameters(); + log("dffmux pattern in %s: dff=%s, mux=%s; removed %d constant bits.\n", log_id(module), log_id(dff), log_id(mux), count); } - log("dffmux pattern in %s: dff=%s, mux=%s; removed %d constant bits.\n", log_id(module), log_id(dff), log_id(mux), count); accept; } endcode -- cgit v1.2.3 From e9eb855d38b3bd4d5a61471af49e791be12817ba Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 11 Sep 2019 13:06:49 -0700 Subject: Make unextend a udata --- passes/pmgen/xilinx_dsp.pmg | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 6e726d1c2..6998d6e84 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,6 +1,6 @@ pattern xilinx_dsp -state > unextend +udata > unextend state clock state sigA sigffAcemuxY sigB sigffBcemuxY sigC sigffCcemuxY sigD sigffDcemuxY sigM sigP state postAddAB postAddMuxAB @@ -23,7 +23,7 @@ match dsp select dsp->type.in(\DSP48E1) endmatch -code unextend sigA sigB sigC sigD sigM +code sigA sigB sigC sigD sigM unextend = [](const SigSpec &sig) { int i; for (i = GetSize(sig)-1; i > 0; i--) @@ -396,7 +396,6 @@ endcode subpattern out_dffe arg argD argQ clock -arg unextend code dff = nullptr; -- cgit v1.2.3 From 4937917cd8fb351740ffd936ea8a227795872775 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 11 Sep 2019 13:22:52 -0700 Subject: Cleanup --- passes/pmgen/peepopt_dffmux.pmg | 47 +++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 25 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/peepopt_dffmux.pmg b/passes/pmgen/peepopt_dffmux.pmg index da3a66577..9b4fef76f 100644 --- a/passes/pmgen/peepopt_dffmux.pmg +++ b/passes/pmgen/peepopt_dffmux.pmg @@ -1,30 +1,27 @@ pattern dffmux -state muxAB +state cemuxAB match dff select dff->type == $dff select GetSize(port(dff, \D)) > 1 endmatch -match mux - select mux->type == $mux - select GetSize(port(mux, \Y)) > 1 +match cemux + select cemux->type == $mux + select GetSize(port(cemux, \Y)) > 1 + index port(cemux, \Y) === port(dff, \D) choice AB {\A, \B} - //select port(mux, AB)[GetSize(port(mux, \Y))-1].wire - index port(mux, \Y) === port(dff, \D) - define BA (AB == \A ? \B : \A) - index port(mux, BA) === port(dff, \Q) - set muxAB AB + index port(cemux, AB) === port(dff, \Q) + set cemuxAB AB endmatch code - SigSpec &D = mux->connections_.at(muxAB); + SigSpec &D = cemux->connections_.at(cemuxAB == \A ? \B : \A); SigSpec &Q = dff->connections_.at(\Q); int width = GetSize(D); - SigSpec AB = port(mux, muxAB); - if (AB[width-1] == AB[width-2]) { + if (D[width-1] == D[width-2]) { did_something = true; SigBit sign = D[width-1]; @@ -43,21 +40,21 @@ code } } - mux->connections_.at(\A).remove(i, width-i); - mux->connections_.at(\B).remove(i, width-i); - mux->connections_.at(\Y).remove(i, width-i); - mux->fixup_parameters(); + cemux->connections_.at(\A).remove(i, width-i); + cemux->connections_.at(\B).remove(i, width-i); + cemux->connections_.at(\Y).remove(i, width-i); + cemux->fixup_parameters(); dff->connections_.at(\D).remove(i, width-i); dff->connections_.at(\Q).remove(i, width-i); dff->fixup_parameters(); - log("dffmux pattern in %s: dff=%s, mux=%s; removed top %d bits.\n", log_id(module), log_id(dff), log_id(mux), width-i); + log("dffcemux pattern in %s: dff=%s, cemux=%s; removed top %d bits.\n", log_id(module), log_id(dff), log_id(cemux), width-i); accept; } else { int count = 0; for (int i = width-1; i >= 0; i--) { - if (AB[i].wire) + if (D[i].wire) continue; Wire *w = Q[i].wire; auto it = w->attributes.find(\init); @@ -67,21 +64,21 @@ code else init = State::Sx; - if (init == State::Sx || init == AB[i].data) { + if (init == State::Sx || init == D[i].data) { count++; - module->connect(Q[i], AB[i]); - mux->connections_.at(\A).remove(i); - mux->connections_.at(\B).remove(i); - mux->connections_.at(\Y).remove(i); + module->connect(Q[i], D[i]); + cemux->connections_.at(\A).remove(i); + cemux->connections_.at(\B).remove(i); + cemux->connections_.at(\Y).remove(i); dff->connections_.at(\D).remove(i); dff->connections_.at(\Q).remove(i); } } if (count > 0) { did_something = true; - mux->fixup_parameters(); + cemux->fixup_parameters(); dff->fixup_parameters(); - log("dffmux pattern in %s: dff=%s, mux=%s; removed %d constant bits.\n", log_id(module), log_id(dff), log_id(mux), count); + log("dffcemux pattern in %s: dff=%s, cemux=%s; removed %d constant bits.\n", log_id(module), log_id(dff), log_id(cemux), count); } accept; -- cgit v1.2.3 From bdb5e0f29c3e913fb4e701317105363064b9a7d3 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 11 Sep 2019 13:36:37 -0700 Subject: Cope with presence of reset muxes too --- passes/pmgen/peepopt_dffmux.pmg | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/peepopt_dffmux.pmg b/passes/pmgen/peepopt_dffmux.pmg index 9b4fef76f..60a708616 100644 --- a/passes/pmgen/peepopt_dffmux.pmg +++ b/passes/pmgen/peepopt_dffmux.pmg @@ -1,16 +1,34 @@ pattern dffmux -state cemuxAB +state cemuxAB rstmuxBA +state sigD match dff select dff->type == $dff select GetSize(port(dff, \D)) > 1 endmatch +match rstmux + select rstmux->type == $mux + select GetSize(port(rstmux, \Y)) > 1 + index port(rstmux, \Y) === port(dff, \D) + choice BA {\B, \A} + select port(rstmux, BA).is_fully_const() + set rstmuxBA BA + optional +endmatch + +code sigD + if (rstmux) + sigD = port(rstmux, rstmuxBA == \B ? \A : \B); + else + sigD = port(dff, \D); +endcode + match cemux select cemux->type == $mux select GetSize(port(cemux, \Y)) > 1 - index port(cemux, \Y) === port(dff, \D) + index port(cemux, \Y) === sigD choice AB {\A, \B} index port(cemux, AB) === port(dff, \Q) set cemuxAB AB @@ -19,6 +37,9 @@ endmatch code SigSpec &D = cemux->connections_.at(cemuxAB == \A ? \B : \A); SigSpec &Q = dff->connections_.at(\Q); + Const rst; + if (rstmux) + rst = port(rstmux, rstmuxBA).as_const(); int width = GetSize(D); if (D[width-1] == D[width-2]) { @@ -30,12 +51,12 @@ code for (i = width-1; i >= 2; i--) { if (!is_signed) { module->connect(Q[i], sign); - if (D[i-1] != sign) + if (D[i-1] != sign || (rst.size() && rst[i-1] != rst[width-1])) break; } else { module->connect(Q[i], Q[i-1]); - if (D[i-2] != sign) + if (D[i-2] != sign || (rst.size() && rst[i-1] != rst[width-1])) break; } } -- cgit v1.2.3 From 690b1a064d9c9c85260cbe841beecff538834833 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 11 Sep 2019 13:48:45 -0700 Subject: Add PCOUT -> PCIN non-shifted cascading --- passes/pmgen/xilinx_dsp.cc | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index d9d1bfea4..df3d60e09 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -272,7 +272,6 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("Analysing %s.%s for Xilinx DSP packing.\n", log_id(pm.module), log_id(st.dsp)); Cell *cell = st.dsp; - bit_to_driver.insert(std::make_pair(cell->getPort("\\P")[17], cell)); if (st.preAdd) { log(" preadder %s (%s)\n", log_id(st.preAdd), log_id(st.preAdd->type)); @@ -317,10 +316,10 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) opmode[5] = State::S1; if (opmode[4] != State::S0) { - if (st.postAddMuxAB == "\\A") - st.sigC.extend_u0(48, st.postAdd->getParam("\\B_SIGNED").as_bool()); - else - st.sigC.extend_u0(48, st.postAdd->getParam("\\A_SIGNED").as_bool()); + //if (st.postAddMuxAB == "\\A") + // st.sigC.extend_u0(48, st.postAdd->getParam("\\B_SIGNED").as_bool()); + //else + // st.sigC.extend_u0(48, st.postAdd->getParam("\\A_SIGNED").as_bool()); cell->setPort("\\C", st.sigC); } @@ -436,6 +435,9 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) P.append(pm.module->addWire(NEW_ID, 48-GetSize(P))); cell->setPort("\\P", P); + bit_to_driver.insert(std::make_pair(P[0], cell)); + bit_to_driver.insert(std::make_pair(P[17], cell)); + pm.blacklist(cell); } @@ -489,6 +491,7 @@ struct XilinxDspPass : public Pass { auto f = [&bit_to_driver](xilinx_dsp_pm &pm){ pack_xilinx_dsp(bit_to_driver, pm); }; pm.run_xilinx_dsp(f); + auto &unextend = pm.ud_xilinx_dsp.unextend; // Look for ability to convert C input from another DSP into PCIN // NB: Needs to be done after pattern matcher has folded all // $add cells into the DSP @@ -500,22 +503,26 @@ struct XilinxDspPass : public Pass { SigSpec &opmode = cell->connections_.at("\\OPMODE"); if (opmode.extract(4,3) != Const::from_string("011")) continue; - SigSpec C = pm.sigmap(cell->getPort("\\C")); - if (C.has_const()) + SigSpec C = unextend(pm.sigmap(cell->getPort("\\C"))); + if (!C[0].wire) continue; auto it = bit_to_driver.find(C[0]); if (it == bit_to_driver.end()) continue; auto driver = it->second; - // Unextend C - int i; - for (i = GetSize(C)-1; i > 0; i--) - if (C[i] != C[i-1]) - break; - if (i > 48-17) - continue; - if (driver->getPort("\\P").extract(17, i) == C.extract(0, i)) { + SigSpec P = driver->getPort("\\P"); + if (GetSize(P) >= GetSize(C) && P.extract(0, GetSize(C)) == C) { + cell->setPort("\\C", Const(0, 48)); + Wire *cascade = module->addWire(NEW_ID, 48); + driver->setPort("\\PCOUT", cascade); + cell->setPort("\\PCIN", cascade); + opmode[6] = State::S0; + opmode[5] = State::S0; + opmode[4] = State::S1; + bit_to_driver.erase(it); + } + else if (GetSize(P) >= GetSize(C)+17 && P.extract(17, GetSize(C)) == C) { cell->setPort("\\C", Const(0, 48)); Wire *cascade = module->addWire(NEW_ID, 48); driver->setPort("\\PCOUT", cascade); -- cgit v1.2.3 From 63431fe42a364f257f9d5571433e139d54cd2c11 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 11 Sep 2019 14:17:45 -0700 Subject: Fix UB --- passes/pmgen/peepopt_dffmux.pmg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/peepopt_dffmux.pmg b/passes/pmgen/peepopt_dffmux.pmg index 60a708616..fbabf90f0 100644 --- a/passes/pmgen/peepopt_dffmux.pmg +++ b/passes/pmgen/peepopt_dffmux.pmg @@ -35,8 +35,8 @@ match cemux endmatch code - SigSpec &D = cemux->connections_.at(cemuxAB == \A ? \B : \A); - SigSpec &Q = dff->connections_.at(\Q); + SigSpec D = port(cemux, cemuxAB == \A ? \B : \A); + SigSpec Q = port(dff, \Q); Const rst; if (rstmux) rst = port(rstmux, rstmuxBA).as_const(); -- cgit v1.2.3 From 817ac7c5e051b2f0947bd9cb9044ac7c3e2f089c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 11 Sep 2019 14:17:45 -0700 Subject: Fix UB --- passes/pmgen/peepopt_dffmux.pmg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/peepopt_dffmux.pmg b/passes/pmgen/peepopt_dffmux.pmg index 60a708616..fbabf90f0 100644 --- a/passes/pmgen/peepopt_dffmux.pmg +++ b/passes/pmgen/peepopt_dffmux.pmg @@ -35,8 +35,8 @@ match cemux endmatch code - SigSpec &D = cemux->connections_.at(cemuxAB == \A ? \B : \A); - SigSpec &Q = dff->connections_.at(\Q); + SigSpec D = port(cemux, cemuxAB == \A ? \B : \A); + SigSpec Q = port(dff, \Q); Const rst; if (rstmux) rst = port(rstmux, rstmuxBA).as_const(); -- cgit v1.2.3 From 3a49aa6b4a707f558ec378a25d28c3e0d914cfac Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 11 Sep 2019 14:20:49 -0700 Subject: Tidy up --- passes/pmgen/peepopt_dffmux.pmg | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/peepopt_dffmux.pmg b/passes/pmgen/peepopt_dffmux.pmg index fbabf90f0..c88a52226 100644 --- a/passes/pmgen/peepopt_dffmux.pmg +++ b/passes/pmgen/peepopt_dffmux.pmg @@ -42,6 +42,12 @@ code rst = port(rstmux, rstmuxBA).as_const(); int width = GetSize(D); + SigSpec &ceA = cemux->connections_.at(\A); + SigSpec &ceB = cemux->connections_.at(\B); + SigSpec &ceY = cemux->connections_.at(\Y); + SigSpec &dffD = dff->connections_.at(\D); + SigSpec &dffQ = dff->connections_.at(\Q); + if (D[width-1] == D[width-2]) { did_something = true; @@ -61,12 +67,12 @@ code } } - cemux->connections_.at(\A).remove(i, width-i); - cemux->connections_.at(\B).remove(i, width-i); - cemux->connections_.at(\Y).remove(i, width-i); + ceA.remove(i, width-i); + ceB.remove(i, width-i); + ceY.remove(i, width-i); cemux->fixup_parameters(); - dff->connections_.at(\D).remove(i, width-i); - dff->connections_.at(\Q).remove(i, width-i); + dffD.remove(i, width-i); + dffQ.remove(i, width-i); dff->fixup_parameters(); log("dffcemux pattern in %s: dff=%s, cemux=%s; removed top %d bits.\n", log_id(module), log_id(dff), log_id(cemux), width-i); @@ -88,11 +94,11 @@ code if (init == State::Sx || init == D[i].data) { count++; module->connect(Q[i], D[i]); - cemux->connections_.at(\A).remove(i); - cemux->connections_.at(\B).remove(i); - cemux->connections_.at(\Y).remove(i); - dff->connections_.at(\D).remove(i); - dff->connections_.at(\Q).remove(i); + ceA.remove(i); + ceB.remove(i); + ceY.remove(i); + dffD.remove(i); + dffQ.remove(i); } } if (count > 0) { -- cgit v1.2.3 From 6fa6bf483c5e5ba7d3a467c37f66ecf6be9db7d5 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 11 Sep 2019 16:21:24 -0700 Subject: Rename {A,B} -> {A2,B2} --- passes/pmgen/xilinx_dsp.cc | 28 ++++++++++++++-------------- passes/pmgen/xilinx_dsp.pmg | 39 ++++++++++++++++++++------------------- 2 files changed, 34 insertions(+), 33 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index df3d60e09..52ffa5465 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -258,8 +258,8 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("\n"); log("preAdd: %s\n", log_id(st.preAdd, "--")); log("ffAD: %s %s %s\n", log_id(st.ffAD, "--"), log_id(st.ffADcemux, "--"), log_id(st.ffADrstmux, "--")); - log("ffA: %s %s %s\n", log_id(st.ffA, "--"), log_id(st.ffAcemux, "--"), log_id(st.ffArstmux, "--")); - log("ffB: %s %s %s\n", log_id(st.ffB, "--"), log_id(st.ffBcemux, "--"), log_id(st.ffBrstmux, "--")); + log("ffA2: %s %s %s\n", log_id(st.ffA2, "--"), log_id(st.ffA2cemux, "--"), log_id(st.ffA2rstmux, "--")); + log("ffB2: %s %s %s\n", log_id(st.ffB2, "--"), log_id(st.ffB2cemux, "--"), log_id(st.ffB2rstmux, "--")); log("ffC: %s %s %s\n", log_id(st.ffC, "--"), log_id(st.ffCcemux, "--"), log_id(st.ffCrstmux, "--")); log("ffD: %s %s %s\n", log_id(st.ffD, "--"), log_id(st.ffDcemux, "--"), log_id(st.ffDrstmux, "--")); log("dsp: %s\n", log_id(st.dsp, "--")); @@ -367,16 +367,16 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) } }; - if (st.ffA) { - SigSpec &A = cell->connections_.at("\\A"); - f(A, st.ffA, st.ffAcemux, st.ffAcepol, "\\CEA2", st.ffArstmux, st.ffArstpol, "\\RSTA"); - pm.add_siguser(A, cell); + if (st.ffA2) { + SigSpec &A2 = cell->connections_.at("\\A"); + f(A2, st.ffA2, st.ffA2cemux, st.ffA2cepol, "\\CEA2", st.ffA2rstmux, st.ffArstpol, "\\RSTA"); + pm.add_siguser(A2, cell); cell->setParam("\\AREG", 1); } - if (st.ffB) { - SigSpec &B = cell->connections_.at("\\B"); - f(B, st.ffB, st.ffBcemux, st.ffBcepol, "\\CEB2", st.ffBrstmux, st.ffBrstpol, "\\RSTB"); - pm.add_siguser(B, cell); + if (st.ffB2) { + SigSpec &B2 = cell->connections_.at("\\B"); + f(B2, st.ffB2, st.ffB2cemux, st.ffB2cepol, "\\CEB2", st.ffB2rstmux, st.ffBrstpol, "\\RSTB"); + pm.add_siguser(B2, cell); cell->setParam("\\BREG", 1); } if (st.ffC) { @@ -406,14 +406,14 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log(" clock: %s (%s)", log_signal(st.clock), "posedge"); - if (st.ffA) - log(" ffA:%s", log_id(st.ffA)); + if (st.ffA2) + log(" ffA2:%s", log_id(st.ffA2)); if (st.ffAD) log(" ffAD:%s", log_id(st.ffAD)); - if (st.ffB) - log(" ffB:%s", log_id(st.ffB)); + if (st.ffB2) + log(" ffB2:%s", log_id(st.ffB2)); if (st.ffC) log(" ffC:%s", log_id(st.ffC)); diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 6998d6e84..8c7477efa 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -4,10 +4,11 @@ udata > unextend state clock state sigA sigffAcemuxY sigB sigffBcemuxY sigC sigffCcemuxY sigD sigffDcemuxY sigM sigP state postAddAB postAddMuxAB -state ffAcepol ffADcepol ffBcepol ffCcepol ffDcepol ffMcepol ffPcepol +state ffA1cepol ffA2cepol ffADcepol ffB1cepol ffB2cepol ffCcepol ffDcepol ffMcepol ffPcepol state ffArstpol ffADrstpol ffBrstpol ffCrstpol ffDrstpol ffMrstpol ffPrstpol -state ffAD ffADcemux ffADrstmux ffA ffAcemux ffArstmux ffB ffBcemux ffBrstmux ffC ffCcemux ffCrstmux +state ffAD ffADcemux ffADrstmux ffA1 ffA1cemux ffA1rstmux ffA2 ffA2cemux ffA2rstmux +state ffB1 ffB1cemux ffB1rstmux ffB2 ffB2cemux ffB2rstmux ffC ffCcemux ffCrstmux state ffD ffDcemux ffDrstmux ffM ffMcemux ffMrstmux ffP ffPcemux ffPrstmux // subpattern @@ -103,20 +104,20 @@ code sigA sigD } endcode -code argQ ffA ffAcemux ffArstmux ffAcepol ffArstpol sigA clock ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol - // Only search for ffA if there was a pre-adder - // (otherwise ffA would have been matched as ffAD) +code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock ffA2 ffA2cemux ffA2rstmux ffA2cepol ffArstpol + // Only search for ffA2 if there was a pre-adder + // (otherwise ffA2 would have been matched as ffA2) if (preAdd) { if (param(dsp, \AREG).as_int() == 0) { argQ = sigA; subpattern(in_dffe); if (dff) { - ffA = dff; + ffA2 = dff; clock = dffclock; if (dffcemux) { - ffAcemux = dffcemux; - ffArstmux = dffrstmux; - ffAcepol = dffcepol; + ffA2cemux = dffcemux; + ffA2rstmux = dffrstmux; + ffA2cepol = dffcepol; ffArstpol = dffrstpol; } sigA = dffD; @@ -126,26 +127,26 @@ code argQ ffA ffAcemux ffArstmux ffAcepol ffArstpol sigA clock ffAD ffADcemux ff // And if there wasn't a pre-adder, // move AD register to A else if (ffAD) { - log_assert(!ffA && !ffAcemux && !ffArstmux); - std::swap(ffA, ffAD); - std::swap(ffAcemux, ffADcemux); - std::swap(ffArstmux, ffADrstmux); - ffAcepol = ffADcepol; + log_assert(!ffA2 && !ffA2cemux && !ffA2rstmux); + std::swap(ffA2, ffAD); + std::swap(ffA2cemux, ffADcemux); + std::swap(ffA2rstmux, ffADrstmux); + ffA2cepol = ffADcepol; ffArstpol = ffADrstpol; } endcode -code argQ ffB ffBcemux ffBrstmux ffBcepol ffBrstpol sigB clock +code argQ ffB2 ffB2cemux ffB2rstmux ffB2cepol ffBrstpol sigB clock if (param(dsp, \BREG).as_int() == 0) { argQ = sigB; subpattern(in_dffe); if (dff) { - ffB = dff; + ffB2 = dff; clock = dffclock; if (dffcemux) { - ffBcemux = dffcemux; - ffBrstmux = dffrstmux; - ffBcepol = dffcepol; + ffB2cemux = dffcemux; + ffB2rstmux = dffrstmux; + ffB2cepol = dffcepol; ffBrstpol = dffrstpol; } sigB = dffD; -- cgit v1.2.3 From 4369fc17d03d5c1db84823a37ff0f56eb1477e8f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 11 Sep 2019 17:06:37 -0700 Subject: Raise a RuntimeError instead of AssertionError --- passes/pmgen/pmgen.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index 573722d68..335d26f16 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -305,7 +305,8 @@ def process_pmgfile(f, filename): block["states"] = set() for s in line.split()[1:]: - assert s in state_types[current_pattern] + if s not in state_types[current_pattern]: + raise RuntimeError("'%s' not in state_types" % s) block["states"].add(s) codetype = "code" -- cgit v1.2.3 From f3081c20e7a9ac9b69581396999633272096b1e8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 11 Sep 2019 17:16:46 -0700 Subject: Add support for A1 and B1 registers --- passes/pmgen/xilinx_dsp.cc | 59 ++++++++++++++++++++++++++------------ passes/pmgen/xilinx_dsp.pmg | 70 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 105 insertions(+), 24 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 52ffa5465..ae8cd64da 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -259,7 +259,9 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("preAdd: %s\n", log_id(st.preAdd, "--")); log("ffAD: %s %s %s\n", log_id(st.ffAD, "--"), log_id(st.ffADcemux, "--"), log_id(st.ffADrstmux, "--")); log("ffA2: %s %s %s\n", log_id(st.ffA2, "--"), log_id(st.ffA2cemux, "--"), log_id(st.ffA2rstmux, "--")); + log("ffA1: %s %s %s\n", log_id(st.ffA1, "--"), log_id(st.ffA1cemux, "--"), log_id(st.ffA1rstmux, "--")); log("ffB2: %s %s %s\n", log_id(st.ffB2, "--"), log_id(st.ffB2cemux, "--"), log_id(st.ffB2rstmux, "--")); + log("ffB1: %s %s %s\n", log_id(st.ffB1, "--"), log_id(st.ffB1cemux, "--"), log_id(st.ffB1rstmux, "--")); log("ffC: %s %s %s\n", log_id(st.ffC, "--"), log_id(st.ffCcemux, "--"), log_id(st.ffCrstmux, "--")); log("ffD: %s %s %s\n", log_id(st.ffD, "--"), log_id(st.ffDcemux, "--"), log_id(st.ffDrstmux, "--")); log("dsp: %s\n", log_id(st.dsp, "--")); @@ -338,12 +340,14 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) if (rstmux) { SigSpec Y = rstmux->getPort("\\Y"); SigSpec AB = rstmux->getPort(rstpol ? "\\A" : "\\B"); - SigSpec S = rstmux->getPort("\\S"); if (!A.empty()) A.replace(Y, AB); - cell->setPort(rstport, rstpol ? S : pm.module->Not(NEW_ID, S)); + if (rstport != IdString()) { + SigSpec S = rstmux->getPort("\\S"); + cell->setPort(rstport, rstpol ? S : pm.module->Not(NEW_ID, S)); + } } - else + else if (rstport != IdString()) cell->setPort(rstport, State::S0); if (cemux) { SigSpec Y = cemux->getPort("\\Y"); @@ -368,16 +372,26 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) }; if (st.ffA2) { - SigSpec &A2 = cell->connections_.at("\\A"); - f(A2, st.ffA2, st.ffA2cemux, st.ffA2cepol, "\\CEA2", st.ffA2rstmux, st.ffArstpol, "\\RSTA"); - pm.add_siguser(A2, cell); - cell->setParam("\\AREG", 1); + SigSpec &A = cell->connections_.at("\\A"); + f(A, st.ffA2, st.ffA2cemux, st.ffA2cepol, "\\CEA2", st.ffA2rstmux, st.ffArstpol, "\\RSTA"); + pm.add_siguser(A, cell); + if (st.ffA1) { + f(A, st.ffA1, st.ffA1cemux, st.ffA1cepol, "\\CEA1", st.ffA1rstmux, st.ffArstpol, IdString()); + cell->setParam("\\AREG", 2); + } + else + cell->setParam("\\AREG", 1); } if (st.ffB2) { - SigSpec &B2 = cell->connections_.at("\\B"); - f(B2, st.ffB2, st.ffB2cemux, st.ffB2cepol, "\\CEB2", st.ffB2rstmux, st.ffBrstpol, "\\RSTB"); - pm.add_siguser(B2, cell); - cell->setParam("\\BREG", 1); + SigSpec &B = cell->connections_.at("\\B"); + f(B, st.ffB2, st.ffB2cemux, st.ffB2cepol, "\\CEB2", st.ffB2rstmux, st.ffBrstpol, "\\RSTB"); + pm.add_siguser(B, cell); + if (st.ffB1) { + f(B, st.ffB1, st.ffB1cemux, st.ffB1cepol, "\\CEB1", st.ffB1rstmux, st.ffBrstpol, IdString()); + cell->setParam("\\BREG", 2); + } + else + cell->setParam("\\BREG", 1); } if (st.ffC) { SigSpec &C = cell->connections_.at("\\C"); @@ -406,14 +420,20 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log(" clock: %s (%s)", log_signal(st.clock), "posedge"); - if (st.ffA2) + if (st.ffA2) { log(" ffA2:%s", log_id(st.ffA2)); + if (st.ffA1) + log(" ffA1:%s", log_id(st.ffA1)); + } if (st.ffAD) log(" ffAD:%s", log_id(st.ffAD)); - if (st.ffB2) + if (st.ffB2) { log(" ffB2:%s", log_id(st.ffB2)); + if (st.ffB1) + log(" ffB1:%s", log_id(st.ffB1)); + } if (st.ffC) log(" ffC:%s", log_id(st.ffC)); @@ -449,17 +469,18 @@ struct XilinxDspPass : public Pass { log("\n"); log(" xilinx_dsp [options] [selection]\n"); log("\n"); - log("Pack input registers (A, B, C, D, AD; with optional enable/reset), pipeline\n"); - log("registers (M; with optional enable/reset), output registers (P; with optional\n"); - log("enable/reset), pre-adder and/or post-adder into Xilinx DSP resources.\n"); + log("Pack input registers (A2, A1, B2, B1, C, D, AD; with optional enable/reset),\n"); + log("pipeline registers (M; with optional enable/reset), output registers (P; with\n"); + log("optional enable/reset), pre-adder and/or post-adder into Xilinx DSP resources.\n"); log("\n"); log("Multiply-accumulate operations using the post-adder with feedback on the 'C'\n"); log("input will be folded into the DSP. In this scenario only, the 'C' input can be\n"); log("used to override the existing accumulation result with a new value.\n"); log("\n"); - log("Use of the dedicated 'PCOUT' -> 'PCIN' path is detected for 'P' -> 'C' connections\n"); - log("where 'P' is right-shifted by 18-bits and used as an input to the post-adder (a\n"); - log("pattern common for summing partial products to implement wide multiplies).\n"); + log("Use of the dedicated 'PCOUT' -> 'PCIN' cascade path is detected for 'P' -> 'C'\n"); + log("connections (optionally, where 'P' is right-shifted by 18-bits and used as an\n"); + log("input to the post-adder -- a pattern common for summing partial products to\n"); + log("implement wide multipliers).\n"); log("\n"); log("\n"); log("Experimental feature: addition/subtractions less than 12 or 24 bits with the\n"); diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 8c7477efa..fa845b593 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -104,9 +104,9 @@ code sigA sigD } endcode -code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock ffA2 ffA2cemux ffA2rstmux ffA2cepol ffArstpol +code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock ffA2 ffA2cemux ffA2rstmux ffA2cepol ffArstpol ffA1 ffA1cemux ffA1rstmux ffA1cepol // Only search for ffA2 if there was a pre-adder - // (otherwise ffA2 would have been matched as ffA2) + // (otherwise ffA2 would have been matched as ffAD) if (preAdd) { if (param(dsp, \AREG).as_int() == 0) { argQ = sigA; @@ -114,11 +114,13 @@ code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock ffA2 ffA2cem if (dff) { ffA2 = dff; clock = dffclock; + if (dffrstmux) { + ffA2cepol = dffcepol; + ffArstpol = dffrstpol; + } if (dffcemux) { ffA2cemux = dffcemux; ffA2rstmux = dffrstmux; - ffA2cepol = dffcepol; - ffArstpol = dffrstpol; } sigA = dffD; } @@ -134,9 +136,37 @@ code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock ffA2 ffA2cem ffA2cepol = ffADcepol; ffArstpol = ffADrstpol; } + + // Now attempt to match A1 + if (ffA2) { + argQ = sigA; + subpattern(in_dffe); + if (dff) { + if ((ffA2rstmux != nullptr) ^ (dffrstmux != nullptr)) + goto ffA1_end; + if (dffrstmux) { + if (ffArstpol != dffrstpol) + goto ffA1_end; + if (port(ffA2rstmux, \S) != port(dffrstmux, \S)) + goto ffA1_end; + ffA1rstmux = dffrstmux; + } + + ffA1 = dff; + clock = dffclock; + + if (dffcemux) { + ffA1cemux = dffcemux; + ffA1cepol = dffcepol; + } + sigA = dffD; + +ffA1_end: ; + } + } endcode -code argQ ffB2 ffB2cemux ffB2rstmux ffB2cepol ffBrstpol sigB clock +code argQ ffB2 ffB2cemux ffB2rstmux ffB2cepol ffBrstpol sigB clock ffB1 ffB1cemux ffB1rstmux ffB1cepol if (param(dsp, \BREG).as_int() == 0) { argQ = sigB; subpattern(in_dffe); @@ -150,6 +180,35 @@ code argQ ffB2 ffB2cemux ffB2rstmux ffB2cepol ffBrstpol sigB clock ffBrstpol = dffrstpol; } sigB = dffD; + + // Now attempt to match B1 + if (ffB2) { + argQ = sigB; + subpattern(in_dffe); + if (dff) { + if ((ffB2rstmux != nullptr) ^ (dffrstmux != nullptr)) + goto ffB1_end; + if (dffrstmux) { + if (ffBrstpol != dffrstpol) + goto ffB1_end; + if (port(ffB2rstmux, \S) != port(dffrstmux, \S)) + goto ffB1_end; + ffB1rstmux = dffrstmux; + } + + ffB1 = dff; + clock = dffclock; + + if (dffcemux) { + ffB1cemux = dffcemux; + ffB1cepol = dffcepol; + } + sigB = dffD; + +ffB1_end: ; + } + } + } } endcode @@ -387,6 +446,7 @@ code argD if (ffcemux) { dffcemux = ffcemux; dffcepol = ffcepol; + argD = port(ffcemux, ffcepol ? \B : \A); dffD.replace(port(ffcemux, \Y), argD); } else -- cgit v1.2.3 From 4ea34aaacdf6f76e11a83d5eb2a53ba7e75f7c11 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 12 Sep 2019 11:45:02 -0700 Subject: SigSet to use stable compare class --- passes/cmds/scc.cc | 2 +- passes/opt/opt_reduce.cc | 4 ++-- passes/opt/opt_rmdff.cc | 2 +- passes/sat/sat.cc | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'passes') diff --git a/passes/cmds/scc.cc b/passes/cmds/scc.cc index 99f4fbae8..0a4f9e98d 100644 --- a/passes/cmds/scc.cc +++ b/passes/cmds/scc.cc @@ -116,7 +116,7 @@ struct SccWorker } SigPool selectedSignals; - SigSet sigToNextCells; + SigSet> sigToNextCells; for (auto &it : module->wires_) if (design->selected(module, it.second)) diff --git a/passes/opt/opt_reduce.cc b/passes/opt/opt_reduce.cc index 6a8d8cabd..9850775af 100644 --- a/passes/opt/opt_reduce.cc +++ b/passes/opt/opt_reduce.cc @@ -37,7 +37,7 @@ struct OptReduceWorker int total_count; bool did_something; - void opt_reduce(pool &cells, SigSet &drivers, RTLIL::Cell *cell) + void opt_reduce(pool &cells, SigSet> &drivers, RTLIL::Cell *cell) { if (cells.count(cell) == 0) return; @@ -289,7 +289,7 @@ struct OptReduceWorker const IdString type_list[] = { ID($reduce_or), ID($reduce_and) }; for (auto type : type_list) { - SigSet drivers; + SigSet> drivers; pool cells; for (auto &cell_it : module->cells_) { diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc index 0bf74098a..8d4b6b14b 100644 --- a/passes/opt/opt_rmdff.cc +++ b/passes/opt/opt_rmdff.cc @@ -29,7 +29,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN SigMap assign_map, dff_init_map; -SigSet mux_drivers; +SigSet> mux_drivers; dict bit2driver; dict> init_attributes; diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc index 430bba1e8..097fc5a2e 100644 --- a/passes/sat/sat.cc +++ b/passes/sat/sat.cc @@ -61,7 +61,7 @@ struct SatHelper // model variables std::vector shows; SigPool show_signal_pool; - SigSet show_drivers; + SigSet> show_drivers; int max_timestep, timeout; bool gotTimeout; -- cgit v1.2.3 From 3a390733027584071d0cd3b2d99c738ce6f1a829 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 12 Sep 2019 17:10:43 -0700 Subject: Set more ports explicitly --- passes/pmgen/xilinx_dsp.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index ae8cd64da..e0c7823ed 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -44,6 +44,8 @@ static Cell* addDsp(Module *module) { cell->setParam("\\OPMODEREG", 0); cell->setParam("\\PREG", 0); cell->setParam("\\USE_MULT", Const("NONE")); + cell->setParam("\\USE_SIMD", Const("ONE48")); + cell->setParam("\\USE_DPORT", Const("FALSE")); cell->setPort("\\D", Const(0, 24)); cell->setPort("\\INMODE", Const(0, 5)); -- cgit v1.2.3 From a67d63714be52e4a4f789c2a82b6283748db8902 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 13 Sep 2019 13:39:39 +0200 Subject: Fix handling of z_digit "?" and fix optimization of cmp with "z" Signed-off-by: Clifford Wolf --- passes/opt/opt_expr.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'passes') diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 00d7d6063..6cf66fb95 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -953,6 +953,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (b.is_fully_const()) { + if (b.is_fully_undef()) { + RTLIL::SigSpec input = b; + ACTION_DO(ID::Y, Const(State::Sx, GetSize(cell->getPort(ID::Y)))); + } else if (b.as_bool() == (cell->type == ID($eq))) { RTLIL::SigSpec input = b; ACTION_DO(ID::Y, cell->getPort(ID::A)); -- cgit v1.2.3 From 95e80809a5801743fabb2836fa25f3c3732a9a24 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 13 Sep 2019 09:49:15 -0700 Subject: Revert "SigSet to use stable compare class" This reverts commit 4ea34aaacdf6f76e11a83d5eb2a53ba7e75f7c11. --- passes/cmds/scc.cc | 2 +- passes/opt/opt_reduce.cc | 4 ++-- passes/opt/opt_rmdff.cc | 2 +- passes/sat/sat.cc | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'passes') diff --git a/passes/cmds/scc.cc b/passes/cmds/scc.cc index 0a4f9e98d..99f4fbae8 100644 --- a/passes/cmds/scc.cc +++ b/passes/cmds/scc.cc @@ -116,7 +116,7 @@ struct SccWorker } SigPool selectedSignals; - SigSet> sigToNextCells; + SigSet sigToNextCells; for (auto &it : module->wires_) if (design->selected(module, it.second)) diff --git a/passes/opt/opt_reduce.cc b/passes/opt/opt_reduce.cc index 9850775af..6a8d8cabd 100644 --- a/passes/opt/opt_reduce.cc +++ b/passes/opt/opt_reduce.cc @@ -37,7 +37,7 @@ struct OptReduceWorker int total_count; bool did_something; - void opt_reduce(pool &cells, SigSet> &drivers, RTLIL::Cell *cell) + void opt_reduce(pool &cells, SigSet &drivers, RTLIL::Cell *cell) { if (cells.count(cell) == 0) return; @@ -289,7 +289,7 @@ struct OptReduceWorker const IdString type_list[] = { ID($reduce_or), ID($reduce_and) }; for (auto type : type_list) { - SigSet> drivers; + SigSet drivers; pool cells; for (auto &cell_it : module->cells_) { diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc index 8d4b6b14b..0bf74098a 100644 --- a/passes/opt/opt_rmdff.cc +++ b/passes/opt/opt_rmdff.cc @@ -29,7 +29,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN SigMap assign_map, dff_init_map; -SigSet> mux_drivers; +SigSet mux_drivers; dict bit2driver; dict> init_attributes; diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc index 097fc5a2e..430bba1e8 100644 --- a/passes/sat/sat.cc +++ b/passes/sat/sat.cc @@ -61,7 +61,7 @@ struct SatHelper // model variables std::vector shows; SigPool show_signal_pool; - SigSet> show_drivers; + SigSet show_drivers; int max_timestep, timeout; bool gotTimeout; -- cgit v1.2.3 From 9a73adde5016346078f336c296c2a54f44210246 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 13 Sep 2019 16:18:05 -0700 Subject: Explicitly order function arguments --- passes/techmap/alumacc.cc | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'passes') diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc index 5b168d524..034731b87 100644 --- a/passes/techmap/alumacc.cc +++ b/passes/techmap/alumacc.cc @@ -48,14 +48,25 @@ struct AlumaccWorker RTLIL::SigSpec cached_cf, cached_of, cached_sf; RTLIL::SigSpec get_lt() { - if (GetSize(cached_lt) == 0) - cached_lt = is_signed ? alu_cell->module->Xor(NEW_ID, get_of(), get_sf()) : get_cf(); + if (GetSize(cached_lt) == 0) { + if (is_signed) { + get_of(); + get_sf(); + cached_lt = alu_cell->module->Xor(NEW_ID, cached_of, cached_sf); + } + else + cached_lt = get_cf(); + } return cached_lt; } RTLIL::SigSpec get_gt() { - if (GetSize(cached_gt) == 0) - cached_gt = alu_cell->module->Not(NEW_ID, alu_cell->module->Or(NEW_ID, get_lt(), get_eq()), false, alu_cell->get_src_attribute()); + if (GetSize(cached_gt) == 0) { + get_lt(); + get_eq(); + SigSpec Or = alu_cell->module->Or(NEW_ID, cached_lt, cached_eq); + cached_gt = alu_cell->module->Not(NEW_ID, Or, false, alu_cell->get_src_attribute()); + } return cached_gt; } -- cgit v1.2.3 From 14d72c39c385bba3005085815a0d66989a437eff Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 13 Sep 2019 16:33:18 -0700 Subject: Revert "Make one check $shift(x)? only; change testcase to be 8b" This reverts commit e2c2d784c8217e4bcf29fb6b156b6a8285036b80. --- passes/pmgen/peepopt_shiftmul.pmg | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/peepopt_shiftmul.pmg b/passes/pmgen/peepopt_shiftmul.pmg index e1da52182..d4748ae19 100644 --- a/passes/pmgen/peepopt_shiftmul.pmg +++ b/passes/pmgen/peepopt_shiftmul.pmg @@ -50,9 +50,8 @@ code if (GetSize(const_factor_cnst) > 20) reject; - if (shift->type.in($shift, $shiftx)) - if (GetSize(port(shift, \Y)) > const_factor) - reject; + if (GetSize(port(shift, \Y)) > const_factor) + reject; int factor_bits = ceil_log2(const_factor); SigSpec mul_din = port(mul, const_factor_port == \A ? \B : \A); -- cgit v1.2.3 From 0932e23dffe0a270d4e41a0f09c0bf06b6998091 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 18 Sep 2019 09:34:42 -0700 Subject: Separate dffrstmux from dffcemux, fix typos --- passes/pmgen/xilinx_dsp.pmg | 52 ++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 20 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index fa845b593..407489658 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -63,11 +63,13 @@ code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock if (dff) { ffAD = dff; clock = dffclock; + if (dffrstmux) { + ffADrstmux = dffrstmux; + ffADrstpol = dffrstpol; + } if (dffcemux) { ffADcemux = dffcemux; - ffADrstmux = dffrstmux; ffADcepol = dffcepol; - ffADrstpol = dffrstpol; } sigA = dffD; } @@ -115,12 +117,12 @@ code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock ffA2 ffA2cem ffA2 = dff; clock = dffclock; if (dffrstmux) { - ffA2cepol = dffcepol; + ffA2rstmux = dffrstmux; ffArstpol = dffrstpol; } if (dffcemux) { + ffA2cepol = dffcepol; ffA2cemux = dffcemux; - ffA2rstmux = dffrstmux; } sigA = dffD; } @@ -173,11 +175,13 @@ code argQ ffB2 ffB2cemux ffB2rstmux ffB2cepol ffBrstpol sigB clock ffB1 ffB1cemu if (dff) { ffB2 = dff; clock = dffclock; + if (dffrstmux) { + ffB2rstmux = dffrstmux; + ffBrstpol = dffrstpol; + } if (dffcemux) { ffB2cemux = dffcemux; - ffB2rstmux = dffrstmux; ffB2cepol = dffcepol; - ffBrstpol = dffrstpol; } sigB = dffD; @@ -220,11 +224,13 @@ code argQ ffD ffDcemux ffDrstmux ffDcepol ffDrstpol sigD clock if (dff) { ffD = dff; clock = dffclock; + if (dffrstmux) { + ffDrstmux = dffrstmux; + ffDrstpol = dffrstpol; + } if (dffcemux) { ffDcemux = dffcemux; - ffDrstmux = dffrstmux; ffDcepol = dffcepol; - ffDrstpol = dffrstpol; } sigD = dffD; } @@ -238,11 +244,13 @@ code argD ffM ffMcemux ffMrstmux ffMcepol ffMrstpol sigM sigP clock if (dff) { ffM = dff; clock = dffclock; + if (dffrstmux) { + ffMrstmux = dffrstmux; + ffMrstpol = dffrstpol; + } if (dffcemux) { ffMcemux = dffcemux; - ffMrstmux = dffrstmux; ffMcepol = dffcepol; - ffMrstpol = dffrstpol; } sigM = dffQ; } @@ -288,20 +296,22 @@ endcode code argD ffP ffPcemux ffPrstmux ffPcepol ffPrstpol sigP clock if (param(dsp, \PREG).as_int() == 0) { - // If ffMcemux and no postAdd new-value net must have exactly three users: ffMcemux, ffM and ffPcemux - if ((ffMcemux && !postAdd && nusers(sigP) == 3) || - // Otherwise new-value net must have exactly two users: dsp and ffPcemux - ((!ffMcemux || postAdd) && nusers(sigP) == 2)) { + int users = 2; + // If ffMcemux and no postAdd new-value net must have three users: ffMcemux, ffM and ffPcemux + if (ffMcemux && !postAdd) users++; + if (nusers(sigP) == users) { argD = sigP; subpattern(out_dffe); if (dff) { ffP = dff; clock = dffclock; + if (dffrstmux) { + ffPrstmux = dffrstmux; + ffPrstpol = dffrstpol; + } if (dffcemux) { ffPcemux = dffcemux; ffPcepol = dffcepol; - ffPrstmux = dffrstmux; - ffPrstpol = dffrstpol; } sigP = dffQ; } @@ -333,11 +343,13 @@ code argQ ffC ffCcemux ffCrstmux ffCcepol ffCrstpol sigC clock if (dff) { ffC = dff; clock = dffclock; + if (dffrstmux) { + ffCrstmux = dffrstmux; + ffCrstpol = dffrstpol; + } if (dffcemux) { ffCcemux = dffcemux; - ffCrstmux = dffrstmux; ffCcepol = dffcepol; - ffCrstpol = dffrstpol; } sigC = dffD; } @@ -421,7 +433,7 @@ code argD argD = port(ffrstmux, ffrstpol ? \A : \B); dffD.replace(port(ffrstmux, \Y), argD); - // Only search for ffrstmux if argQ has at + // Only search for ffcemux if argQ has at // least 3 users (ff, , ffrstmux) and // dffD only has two (ff, ffrstmux) if (!(nusers(argQ) >= 3 && nusers(dffD) == 2)) @@ -525,7 +537,7 @@ endmatch code argD argQ dffrstmux = ffrstmux; if (ffrstmux) { - SigSpec AB = port(ffrstmux, ffcepol ? \A : \B); + SigSpec AB = port(ffrstmux, ffrstpol ? \A : \B); if (ffoffset + GetSize(argD) > GetSize(AB)) reject; -- cgit v1.2.3 From 1f18736d20787ec3f88b63df2e277e4ca3034415 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 18 Sep 2019 09:39:59 -0700 Subject: Add support for overflow using pattern detector --- passes/pmgen/xilinx_dsp.cc | 19 +++++++++++++++++++ passes/pmgen/xilinx_dsp.pmg | 13 ++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index e0c7823ed..786582cfa 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -271,6 +271,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("postAdd: %s\n", log_id(st.postAdd, "--")); log("postAddMux: %s\n", log_id(st.postAddMux, "--")); log("ffP: %s %s %s\n", log_id(st.ffP, "--"), log_id(st.ffPcemux, "--"), log_id(st.ffPrstmux, "--")); + log("overflow: %s\n", log_id(st.overflow, "--")); #endif log("Analysing %s.%s for Xilinx DSP packing.\n", log_id(pm.module), log_id(st.dsp)); @@ -329,6 +330,24 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) pm.autoremove(st.postAdd); } + if (st.overflow) { + log(" overflow %s (%s)\n", log_id(st.overflow), log_id(st.overflow->type)); + cell->setParam("\\USE_PATTERN_DETECT", Const("PATDET")); + cell->setParam("\\SEL_PATTERN", Const("PATTERN")); + cell->setParam("\\SEL_MASK", Const("MASK")); + + if (st.overflow->type == "$ge") { + int B = st.overflow->getPort("\\B").as_int(); + log_assert((B & (B-1)) == 0); // Exact power of 2 + + cell->setParam("\\MASK", Const(B-1, 48)); + cell->setParam("\\PATTERN", Const(0, 48)); + cell->setPort("\\OVERFLOW", st.overflow->getPort("\\Y")); + } + else log_abort(); + + pm.autoremove(st.overflow); + } if (st.clock != SigBit()) { diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 407489658..b93162a0e 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -264,7 +264,6 @@ match postAdd select postAdd->type.in($add) select GetSize(port(postAdd, \Y)) <= 48 - select nusers(port(postAdd, \Y)) == 2 choice AB {\A, \B} select nusers(port(postAdd, AB)) <= 3 filter ffMcemux || nusers(port(postAdd, AB)) == 2 @@ -356,6 +355,18 @@ code argQ ffC ffCcemux ffCrstmux ffCcepol ffCrstpol sigC clock } endcode +match overflow + if ffP + if dsp->parameters.at(\USE_PATTERN_DETECT, Const("NO_PATDET")).decode_string() == "NO_PATDET" + select overflow->type.in($ge) + select GetSize(port(overflow, \Y)) <= 48 + select port(overflow, \B).is_fully_const() + // Check is exact power of 2 + select (port(overflow, \B).as_int() & (port(overflow, \B).as_int()-1)) == 0 + index port(overflow, \A) === sigP + optional +endmatch + code accept; endcode -- cgit v1.2.3 From 347cbf59bd45345663defa9c99c7fc6563404da6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 18 Sep 2019 12:16:03 -0700 Subject: Check overflow condition is power of 2 without using int32 --- passes/pmgen/xilinx_dsp.cc | 16 +++++++++++++--- passes/pmgen/xilinx_dsp.pmg | 4 ++-- 2 files changed, 15 insertions(+), 5 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 786582cfa..8500a6072 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -337,10 +337,20 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) cell->setParam("\\SEL_MASK", Const("MASK")); if (st.overflow->type == "$ge") { - int B = st.overflow->getPort("\\B").as_int(); - log_assert((B & (B-1)) == 0); // Exact power of 2 + Const B = st.overflow->getPort("\\B").as_const(); + log_assert(std::count(B.bits.begin(), B.bits.end(), State::S1) == 1); + // Since B is an exact power of 2, subtract 1 + // by inverting all bits up until hitting + // that one hi bit + for (auto &b : B.bits) + if (b == State::S0) b = State::S1; + else if (b == State::S1) { + b = State::S0; + break; + } + B.extu(48); - cell->setParam("\\MASK", Const(B-1, 48)); + cell->setParam("\\MASK", B); cell->setParam("\\PATTERN", Const(0, 48)); cell->setPort("\\OVERFLOW", st.overflow->getPort("\\Y")); } diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index b93162a0e..08cb1f51b 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -361,8 +361,8 @@ match overflow select overflow->type.in($ge) select GetSize(port(overflow, \Y)) <= 48 select port(overflow, \B).is_fully_const() - // Check is exact power of 2 - select (port(overflow, \B).as_int() & (port(overflow, \B).as_int()-1)) == 0 + define B port(overflow, \B).as_const() + select std::count(B.bits.begin(), B.bits.end(), State::S1) == 1 index port(overflow, \A) === sigP optional endmatch -- cgit v1.2.3 From 44bf4ac35cf9f4fa81b8c9ae7f6e2f724e11934d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 18 Sep 2019 12:35:24 -0700 Subject: Add doc on pattern detector for overflow --- passes/pmgen/xilinx_dsp.cc | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 8500a6072..5af48e4d2 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -2,6 +2,7 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf + * 2019 Eddie Hung * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -519,6 +520,10 @@ struct XilinxDspPass : public Pass { log("the add/subtract operator will cause those operations to be implemented using\n"); log("the 'SIMD' feature of DSPs.\n"); log("\n"); + log("Experimental feature: the presence of a `$ge' cell attached to the registered\n"); + log("P output implementing the operation \"(P >= )\" will be transformed\n"); + log("into using the DSP48E1's pattern detector feature for overflow detection.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { -- cgit v1.2.3 From 70c607d7dde23b709ffd36c47680cddcc4666fcd Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 13:28:15 -0700 Subject: Document (* gentb_skip *) attr for test_autotb --- passes/tests/test_autotb.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'passes') diff --git a/passes/tests/test_autotb.cc b/passes/tests/test_autotb.cc index bfb1d6642..a5ac3130f 100644 --- a/passes/tests/test_autotb.cc +++ b/passes/tests/test_autotb.cc @@ -345,6 +345,9 @@ struct TestAutotbBackend : public Backend { log("value after initialization. This can e.g. be used to force a reset signal\n"); log("low in order to explore more inner states in a state machine.\n"); log("\n"); + log("The attribute 'gentb_skip' can be attached to modules to suppress testbench\n"); + log("generation.\n"); + log("\n"); log(" -n \n"); log(" number of iterations the test bench should run (default = 1000)\n"); log("\n"); -- cgit v1.2.3 From c9f9518de4af34b2539d230c0894b04d174b755d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Wed, 28 Aug 2019 14:58:14 +0000 Subject: Added extractinv pass --- passes/techmap/Makefile.inc | 1 + passes/techmap/extractinv.cc | 123 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 passes/techmap/extractinv.cc (limited to 'passes') diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index 631a80aa5..cd357d72a 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -40,6 +40,7 @@ OBJS += passes/techmap/attrmap.o OBJS += passes/techmap/zinit.o OBJS += passes/techmap/dff2dffs.o OBJS += passes/techmap/flowmap.o +OBJS += passes/techmap/extractinv.o endif GENFILES += passes/techmap/techmap.inc diff --git a/passes/techmap/extractinv.cc b/passes/techmap/extractinv.cc new file mode 100644 index 000000000..dda71f12a --- /dev/null +++ b/passes/techmap/extractinv.cc @@ -0,0 +1,123 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2019 Marcin KoÅ›cielnicki + * + * 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 + +void split_portname_pair(std::string &port1, std::string &port2) +{ + size_t pos = port1.find_first_of(':'); + if (pos != std::string::npos) { + port2 = port1.substr(pos+1); + port1 = port1.substr(0, pos); + } +} + +struct ExtractinvPass : public Pass { + ExtractinvPass() : Pass("extractinv", "extract explicit inverter cells for invertible cell pins") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" extractinv [options] [selection]\n"); + log("\n"); + log("Searches the design for all cells with invertible pins controlled by a cell\n"); + log("parameter (eg. IS_CLK_INVERTED on many Xilinx cells) and removes the parameter.\n"); + log("If the parameter was set to 1, inserts an explicit inverter cell in front of\n"); + log("the pin instead. Normally used for output to ISE, which does not support the\n"); + log("inversion parameters.\n"); + log("\n"); + log("To mark a cell port as invertible, use (* invertible_pin = \"param_name\" *)\n"); + log("on the wire in the blackbox module. The parameter value should have\n"); + log("the same width as the port, and will be effectively XORed with it.\n"); + log("\n"); + log(" -inv :\n"); + log(" Specifies the cell type to use for the inverters and its port names.\n"); + log(" This option is required.\n"); + log("\n"); + } + + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing EXTRACTINV pass (extracting pin inverters).\n"); + + std::string inv_celltype, inv_portname, inv_portname2; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + std::string arg = args[argidx]; + if (arg == "-inv" && argidx+2 < args.size()) { + inv_celltype = args[++argidx]; + inv_portname = args[++argidx]; + split_portname_pair(inv_portname, inv_portname2); + continue; + } + break; + } + extra_args(args, argidx, design); + + if (inv_celltype.empty()) + log_error("The -inv option is required.\n"); + + for (auto module : design->selected_modules()) + { + for (auto cell : module->selected_cells()) + for (auto port : cell->connections()) { + auto cell_module = design->module(cell->type); + if (!cell_module) + continue; + auto cell_wire = cell_module->wire(port.first); + if (!cell_wire) + continue; + auto it = cell_wire->attributes.find("\\invertible_pin"); + if (it == cell_wire->attributes.end()) + continue; + IdString param_name = RTLIL::escape_id(it->second.decode_string()); + auto it2 = cell->parameters.find(param_name); + // Inversion not used -- skip. + if (it2 == cell->parameters.end()) + continue; + SigSpec sig = port.second; + if (it2->second.size() != sig.size()) + log_error("The inversion parameter needs to be the same width as the port (%s.%s port %s parameter %s)", log_id(module->name), log_id(cell->type), log_id(port.first), log_id(param_name)); + RTLIL::Const invmask = it2->second; + cell->parameters.erase(param_name); + if (invmask.is_fully_zero()) + continue; + Wire *iwire = module->addWire(NEW_ID, sig.size()); + for (int i = 0; i < sig.size(); i++) + if (invmask[i] == State::S1) { + RTLIL::Cell *icell = module->addCell(NEW_ID, RTLIL::escape_id(inv_celltype)); + icell->setPort(RTLIL::escape_id(inv_portname), SigSpec(iwire, i)); + icell->setPort(RTLIL::escape_id(inv_portname2), sig[i]); + log("Inserting %s on %s.%s.%s[%d].\n", inv_celltype.c_str(), log_id(module), log_id(cell->type), log_id(port.first), i); + sig[i] = SigBit(iwire, i); + } + cell->setPort(port.first, sig); + } + } + } +} ExtractinvPass; + +PRIVATE_NAMESPACE_END -- cgit v1.2.3 From 29d446d7584b772a2dbac92a3088f93223ff7f86 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 19 Sep 2019 10:39:00 -0700 Subject: Cleanup --- passes/pmgen/xilinx_dsp.pmg | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 08cb1f51b..31ab75f09 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -398,10 +398,8 @@ endmatch code argQ argD { - if (clock != SigBit()) { - if (port(ff, \CLK) != clock) - reject; - } + if (clock != SigBit() && port(ff, \CLK) != clock) + reject; SigSpec Q = port(ff, \Q); if (ffoffset + GetSize(argQ) > GetSize(Q)) @@ -580,10 +578,8 @@ endmatch code argQ if (ff) { - if (clock != SigBit()) { - if (port(ff, \CLK) != clock) - reject; - } + if (clock != SigBit() && port(ff, \CLK) != clock) + reject; SigSpec D = port(ff, \D); if (ffoffset + GetSize(argD) > GetSize(D)) -- cgit v1.2.3 From b76fac3ac3a815568827a03b201f386b2577e010 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 19 Sep 2019 19:26:09 +0200 Subject: Add techmap_autopurge attribute, fixes #1381 Signed-off-by: Clifford Wolf --- passes/techmap/techmap.cc | 54 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 5 deletions(-) (limited to 'passes') diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 51a65aea6..cf40b2f17 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -206,10 +206,27 @@ struct TechmapWorker std::map positional_ports; dict temp_renamed_wires; + pool autopurge_tpl_bits; - for (auto &it : tpl->wires_) { + for (auto &it : tpl->wires_) + { if (it.second->port_id > 0) - positional_ports[stringf("$%d", it.second->port_id)] = it.first; + { + IdString posportname = stringf("$%d", it.second->port_id); + positional_ports[posportname] = it.first; + + if (!flatten_mode && it.second->get_bool_attribute(ID(techmap_autopurge)) && + (!cell->hasPort(it.second->name) || !GetSize(cell->getPort(it.second->name))) && + (!cell->hasPort(posportname) || !GetSize(cell->getPort(posportname)))) + { + if (sigmaps.count(tpl) == 0) + sigmaps[tpl].set(tpl); + + for (auto bit : sigmaps.at(tpl)(it.second)) + if (bit.wire != nullptr) + autopurge_tpl_bits.insert(it.second); + } + } IdString w_name = it.second->name; apply_prefix(cell->name, w_name); RTLIL::Wire *w = module->wire(w_name); @@ -232,6 +249,8 @@ struct TechmapWorker w->port_input = false; w->port_output = false; w->port_id = 0; + if (!flatten_mode) + w->attributes.erase(ID(techmap_autopurge)); if (it.second->get_bool_attribute(ID(_techmap_special_))) w->attributes.clear(); if (w->attributes.count(ID(src))) @@ -362,11 +381,31 @@ struct TechmapWorker if (!flatten_mode && c->type.begins_with("\\$")) c->type = c->type.substr(1); - for (auto &it2 : c->connections_) { - apply_prefix(cell->name, it2.second, module); - port_signal_map.apply(it2.second); + vector autopurge_ports; + + for (auto &it2 : c->connections_) + { + bool autopurge = false; + if (!autopurge_tpl_bits.empty()) { + autopurge = GetSize(it2.second) != 0; + for (auto &bit : sigmaps.at(tpl)(it2.second)) + if (!autopurge_tpl_bits.count(bit)) { + autopurge = false; + break; + } + } + + if (autopurge) { + autopurge_ports.push_back(it2.first); + } else { + apply_prefix(cell->name, it2.second, module); + port_signal_map.apply(it2.second); + } } + for (auto &it2 : autopurge_ports) + c->unsetPort(it2); + if (c->type.in(ID($memrd), ID($memwr), ID($meminit))) { IdString memid = c->getParam(ID(MEMID)).decode_string(); log_assert(memory_renames.count(memid) != 0); @@ -1064,6 +1103,11 @@ struct TechmapPass : public Pass { log("will create a wrapper for the cell and then run the command string that the\n"); log("attribute is set to on the wrapper module.\n"); log("\n"); + log("When a port on a module in the map file has the 'techmap_autopurge' attribute\n"); + log("set, and that port is not connected in the instantiation that is mapped, then\n"); + log("then a cell port connected only to such wires will be omitted in the mapped\n"); + log("version of the circuit.\n"); + log("\n"); log("All wires in the modules from the map file matching the pattern _TECHMAP_*\n"); log("or *._TECHMAP_* are special wires that are used to pass instructions from\n"); log("the mapping module to the techmap command. At the moment the following special\n"); -- cgit v1.2.3 From c8310a6e768991f7499f250542eeda3503d3977c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 19 Sep 2019 12:00:48 -0700 Subject: Refactor ice40_dsp.pmg --- passes/pmgen/ice40_dsp.cc | 51 ++-- passes/pmgen/ice40_dsp.pmg | 569 ++++++++++++++++++++++++++++++++------------- 2 files changed, 426 insertions(+), 194 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 68fc29f31..4132857d6 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -31,12 +31,12 @@ void create_ice40_dsp(ice40_dsp_pm &pm) #if 1 log("\n"); - log("ffA: %s\n", log_id(st.ffA, "--")); - log("ffB: %s\n", log_id(st.ffB, "--")); + log("ffA: %s %s %s\n", log_id(st.ffA, "--"), log_id(st.ffAcemux, "--"), log_id(st.ffArstmux, "--")); + log("ffB: %s %s %s\n", log_id(st.ffB, "--"), log_id(st.ffBcemux, "--"), log_id(st.ffBrstmux, "--")); log("mul: %s\n", log_id(st.mul, "--")); - log("ffFJKG: %s\n", log_id(st.ffFJKG, "--")); - log("addAB: %s\n", log_id(st.addAB, "--")); - log("muxAB: %s\n", log_id(st.muxAB, "--")); + log("ffFJKG: %s n/a %s\n", log_id(st.ffFJKG, "--"), log_id(st.ffFJKGrstmux, "--")); + log("add: %s\n", log_id(st.add, "--")); + log("mux: %s\n", log_id(st.mux, "--")); log("ffO: %s\n", log_id(st.ffO, "--")); #endif @@ -146,10 +146,10 @@ void create_ice40_dsp(ice40_dsp_pm &pm) SigSpec O = st.sigO; int O_width = GetSize(O); if (O_width == 33) { - log_assert(st.addAB); + log_assert(st.add); // If we have a signed multiply-add, then perform sign extension // TODO: Need to check CD[31:16] is sign extension of CD[15:0]? - if (st.addAB->getParam("\\A_SIGNED").as_bool() && st.addAB->getParam("\\B_SIGNED").as_bool()) + if (st.add->getParam("\\A_SIGNED").as_bool() && st.add->getParam("\\B_SIGNED").as_bool()) pm.module->connect(O[32], O[31]); else cell->setPort("\\CO", O[32]); @@ -164,18 +164,14 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setPort("\\O", O); bool accum = false; - if (st.addAB) { - if (st.addA) - accum = (st.ffO && st.addAB->getPort("\\B") == st.sigO); - else if (st.addB) - accum = (st.ffO && st.addAB->getPort("\\A") == st.sigO); - else log_abort(); + if (st.add) { + accum = (st.ffO && st.add->getPort(st.addAB == "\\A" ? "\\B" : "\\A") == st.sigO); if (accum) - log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); + log(" accumulator %s (%s)\n", log_id(st.add), log_id(st.add->type)); else - log(" adder %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); - cell->setPort("\\ADDSUBTOP", st.addAB->type == "$add" ? State::S0 : State::S1); - cell->setPort("\\ADDSUBBOT", st.addAB->type == "$add" ? State::S0 : State::S1); + log(" adder %s (%s)\n", log_id(st.add), log_id(st.add->type)); + cell->setPort("\\ADDSUBTOP", st.add->type == "$add" ? State::S0 : State::S1); + cell->setPort("\\ADDSUBBOT", st.add->type == "$add" ? State::S0 : State::S1); } else { cell->setPort("\\ADDSUBTOP", State::S0); cell->setPort("\\ADDSUBBOT", State::S0); @@ -188,10 +184,12 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setPort("\\OHOLDBOT", State::S0); SigSpec acc_reset = State::S0; - if (st.muxA) - acc_reset = st.muxA->getPort("\\S"); - if (st.muxB) - acc_reset = pm.module->Not(NEW_ID, st.muxB->getPort("\\S")); + if (st.mux) { + if (st.muxAB == "\\A") + acc_reset = st.mux->getPort("\\S"); + else + acc_reset = pm.module->Not(NEW_ID, st.mux->getPort("\\S")); + } cell->setPort("\\OLOADTOP", acc_reset); cell->setPort("\\OLOADBOT", acc_reset); @@ -219,8 +217,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam("\\B_SIGNED", st.mul->getParam("\\B_SIGNED").as_bool()); if (st.ffO) { - if (st.ffO_lo) - cell->setParam("\\TOPOUTPUT_SELECT", Const(st.addAB ? 0 : 3, 2)); + if (st.o_lo) + cell->setParam("\\TOPOUTPUT_SELECT", Const(st.add ? 0 : 3, 2)); else cell->setParam("\\TOPOUTPUT_SELECT", Const(1, 2)); @@ -228,8 +226,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam("\\BOTOUTPUT_SELECT", Const(1, 2)); } else { - cell->setParam("\\TOPOUTPUT_SELECT", Const(st.addAB ? 0 : 3, 2)); - cell->setParam("\\BOTOUTPUT_SELECT", Const(st.addAB ? 0 : 3, 2)); + cell->setParam("\\TOPOUTPUT_SELECT", Const(st.add ? 0 : 3, 2)); + cell->setParam("\\BOTOUTPUT_SELECT", Const(st.add ? 0 : 3, 2)); } if (cell != st.mul) @@ -237,7 +235,7 @@ void create_ice40_dsp(ice40_dsp_pm &pm) else pm.blacklist(st.mul); pm.autoremove(st.ffFJKG); - pm.autoremove(st.addAB); + pm.autoremove(st.add); } struct Ice40DspPass : public Pass { @@ -249,6 +247,7 @@ struct Ice40DspPass : public Pass { log(" ice40_dsp [options] [selection]\n"); log("\n"); log("Map multipliers and multiply-accumulate blocks to iCE40 DSP resources.\n"); + log("Currently, only the 16x16 multiply mode is supported and not the 2 x 8x8 mode.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index fbf498109..22267aea7 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -1,9 +1,25 @@ pattern ice40_dsp state clock -state clock_pol cd_signed +state clock_pol cd_signed o_lo state sigA sigB sigCD sigH sigO -state addAB muxAB +state add mux +state addAB muxAB + +state ffAcepol ffBcepol ffCDcepol ffOcepol +state ffArstpol ffBrstpol ffCDrstpol ffFJKGrstpol ffOrstpol + +state ffA ffAcemux ffArstmux ffB ffBcemux ffBrstmux ffCD ffCDcemux ffCDrstmux +state ffFJKG ffFJKGrstmux ffO ffOcemux ffOrstmux + +// subpattern +state argQ argD +state ffcepol ffrstpol +state ffoffset +udata dffD dffQ +udata dffclock +udata dff dffcemux dffrstmux +udata dffcepol dffrstpol dffclock_pol match mul select mul->type.in($mul, \SB_MAC16) @@ -47,226 +63,443 @@ code sigA sigB sigH log_assert(nusers(O.extract_end(i)) <= 1); endcode -match ffA - if mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool() - select ffA->type.in($dff) - filter GetSize(port(ffA, \Q)) >= GetSize(sigA) - slice offset GetSize(port(ffA, \Q)) - filter offset+GetSize(sigA) <= GetSize(port(ffA, \Q)) && port(ffA, \Q).extract(offset, GetSize(sigA)) == sigA - optional -endmatch +code argQ ffA ffAcemux ffArstmux ffAcepol ffArstpol sigA clock clock_pol + if (mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool()) { + argQ = sigA; + subpattern(in_dffe); + if (dff) { + ffA = dff; + clock = dffclock; + clock_pol = dffclock_pol; + if (dffrstmux) { + ffArstmux = dffrstmux; + ffArstpol = dffrstpol; + } + if (dffcemux) { + ffAcemux = dffcemux; + ffAcepol = dffcepol; + } + sigA = dffD; + } + } +endcode -code sigA clock clock_pol - if (ffA) { - for (auto b : port(ffA, \Q)) - if (b.wire->get_bool_attribute(\keep)) - reject; +code argQ ffB ffBcemux ffBrstmux ffBcepol ffBrstpol sigB clock clock_pol + if (mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool()) { + argQ = sigB; + subpattern(in_dffe); + if (dff) { + ffB = dff; + clock = dffclock; + clock_pol = dffclock_pol; + if (dffrstmux) { + ffBrstmux = dffrstmux; + ffBrstpol = dffrstpol; + } + if (dffcemux) { + ffBcemux = dffcemux; + ffBcepol = dffcepol; + } + sigB = dffD; + } + } +endcode - clock = port(ffA, \CLK).as_bit(); - clock_pol = param(ffA, \CLK_POLARITY).as_bool(); +code argD ffFJKG ffFJKGrstmux ffFJKGrstpol sigH sigO clock clock_pol + if (nusers(sigH) == 2 && + (mul->type != \SB_MAC16 || + (!param(mul, \TOP_8x8_MULT_REG).as_bool() && !param(mul, \BOT_8x8_MULT_REG).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG2).as_bool()))) { + argD = sigH; + subpattern(out_dffe); + if (dff) { + ffFJKG = dff; + clock = dffclock; + clock_pol = dffclock_pol; + if (dffrstmux) { + ffFJKGrstmux = dffrstmux; + ffFJKGrstpol = dffrstpol; + } + // F/J/K/G do not have a CE-like (hold) input + if (dffcemux) + reject; - sigA.replace(port(ffA, \Q), port(ffA, \D)); + // Reset signal of F/J (IRSTTOP) and K/G (IRSTBOT) + // shared with A and B + if ((ffArstmux != NULL) != (ffFJKGrstmux != NULL)) + reject; + if ((ffBrstmux != NULL) != (ffFJKGrstmux != NULL)) + reject; + if (ffArstmux) { + if (port(ffArstmux, \S) != port(ffFJKGrstmux, \S)) + reject; + if (ffArstpol != ffFJKGrstpol) + reject; + } + if (ffBrstmux) { + if (port(ffBrstmux, \S) != port(ffFJKGrstmux, \S)) + reject; + if (ffBrstpol != ffFJKGrstpol) + reject; + } + + sigH = dffQ; + } } + + sigO = sigH; endcode -match ffB - if mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool() - select ffB->type.in($dff) - filter GetSize(port(ffB, \Q)) >= GetSize(sigB) - slice offset GetSize(port(ffB, \Q)) - filter offset+GetSize(sigB) <= GetSize(port(ffB, \Q)) && port(ffB, \Q).extract(offset, GetSize(sigB)) == sigB +match add + if mul->type != \SB_MAC16 || (param(mul, \TOPOUTPUT_SELECT).as_int() == 3 && param(mul, \BOTOUTPUT_SELECT).as_int() == 3) + select add->type.in($add) + choice AB {\A, \B} + select nusers(port(add, AB)) == 2 + index port(add, AB)[0] === sigH[0] + filter GetSize(port(add, AB)) <= GetSize(sigH) + filter port(add, AB) == sigH.extract(0, GetSize(port(add, AB))) + set addAB AB optional endmatch -code sigB clock clock_pol - if (ffB) { - for (auto b : port(ffB, \Q)) - if (b.wire->get_bool_attribute(\keep)) - reject; +code sigCD sigO cd_signed + if (add) { + sigCD = port(add, addAB == \A ? \B : \A); + cd_signed = param(add, addAB == \A ? \B_SIGNED : \A_SIGNED).as_bool(); - SigBit c = port(ffB, \CLK).as_bit(); - bool cp = param(ffB, \CLK_POLARITY).as_bool(); + int natural_mul_width = GetSize(sigA) + GetSize(sigB); + int actual_mul_width = GetSize(sigH); + int actual_acc_width = GetSize(sigCD); - if (clock != SigBit() && (c != clock || cp != clock_pol)) + if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width)) + reject; + // If accumulator, check adder width and signedness + if (sigCD == sigH && (actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(add, \A_SIGNED).as_bool())) reject; - clock = c; - clock_pol = cp; - - sigB.replace(port(ffB, \Q), port(ffB, \D)); + sigO = port(add, \Y); } endcode -match ffFJKG - // Ensure pipeline register is not already used - if mul->type != \SB_MAC16 || (!param(mul, \TOP_8x8_MULT_REG).as_bool() && !param(mul, \BOT_8x8_MULT_REG).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG2).as_bool()) - select ffFJKG->type.in($dff) - select nusers(port(ffFJKG, \D)) == 2 - index port(ffFJKG, \D) === sigH +match mux + select mux->type == $mux + choice AB {\A, \B} + index nusers(port(mux, AB)) === 2 + index port(mux, AB) === sigO + set muxAB AB optional endmatch -code sigH sigO clock clock_pol - if (ffFJKG) { - sigH = port(ffFJKG, \Q); - for (auto b : sigH) - if (b.wire->get_bool_attribute(\keep)) - reject; +code sigO + if (mux) + sigO = port(mux, \Y); +endcode - SigBit c = port(ffFJKG, \CLK).as_bit(); - bool cp = param(ffFJKG, \CLK_POLARITY).as_bool(); +code argD ffO ffOcemux ffOrstmux ffOcepol ffOrstpol sigO sigCD clock clock_pol cd_signed o_lo + if (mul->type != \SB_MAC16 || + // Ensure that register is not already used + ((mul->parameters.at(\TOPOUTPUT_SELECT, 0).as_int() != 1 && mul->parameters.at(\BOTOUTPUT_SELECT, 0).as_int() != 1) && + // Ensure that OLOADTOP/OLOADBOT is unused or zero + (mul->connections_.at(\OLOADTOP, State::S0).is_fully_zero() && mul->connections_.at(\OLOADBOT, State::S0).is_fully_zero()))) { - if (clock != SigBit() && (c != clock || cp != clock_pol)) - reject; + dff = nullptr; + + // First try entire sigO + if (nusers(sigO) == 2) { + argD = sigO; + subpattern(out_dffe); + } - clock = c; - clock_pol = cp; + // Otherwise try just its least significant 16 bits + if (!dff && GetSize(sigO) > 16) { + argD = sigO.extract(0, 16); + if (nusers(argD) == 2) { + subpattern(out_dffe); + o_lo = dff; + } + } + + if (dff) { + ffO = dff; + clock = dffclock; + clock_pol = dffclock_pol; + if (dffrstmux) { + ffOrstmux = dffrstmux; + ffOrstpol = dffrstpol; + } + if (dffcemux) { + ffOcemux = dffcemux; + ffOcepol = dffcepol; + } + + sigO.replace(sigO.extract(0, GetSize(dffQ)), dffQ); + } + + // Loading value into output register is not + // supported unless using accumulator + if (mux) { + if (sigCD != sigO) + reject; + sigCD = port(mux, muxAB == \B ? \A : \B); + + cd_signed = add && param(add, \A_SIGNED).as_bool() && param(add, \B_SIGNED).as_bool(); + } } + sigCD.extend_u0(32, cd_signed); +endcode - sigO = sigH; +code + accept; endcode -match addA - select addA->type.in($add) - select nusers(port(addA, \A)) == 2 - filter param(addA, \A_WIDTH).as_int() <= GetSize(sigH) - //index port(addA, \A) === sigH.extract(0, param(addA, \A_WIDTH).as_int()) - filter port(addA, \A) == sigH.extract(0, param(addA, \A_WIDTH).as_int()) - optional -endmatch +// ####################### -match addB - if !addA - select addB->type.in($add, $sub) - select nusers(port(addB, \B)) == 2 - filter param(addB, \B_WIDTH).as_int() <= GetSize(sigH) - //index port(addB, \B) === sigH.extract(0, param(addB, \B_WIDTH).as_int()) - filter port(addB, \B) == sigH.extract(0, param(addB, \B_WIDTH).as_int()) - optional -endmatch +subpattern in_dffe +arg argD argQ clock clock_pol -code addAB sigCD sigO cd_signed - if (addA) { - addAB = addA; - sigCD = port(addAB, \B); - cd_signed = param(addAB, \B_SIGNED).as_bool(); - } - else if (addB) { - addAB = addB; - sigCD = port(addAB, \A); - cd_signed = param(addAB, \A_SIGNED).as_bool(); +code + dff = nullptr; + for (auto c : argQ.chunks()) { + if (!c.wire) + reject; + if (c.wire->get_bool_attribute(\keep)) + reject; } - if (addAB) { - if (mul->type == \SB_MAC16) { - // Ensure that adder is not used - if (param(mul, \TOPOUTPUT_SELECT).as_int() != 3 || - param(mul, \BOTOUTPUT_SELECT).as_int() != 3) - reject; - } +endcode - int natural_mul_width = GetSize(sigA) + GetSize(sigB); - int actual_mul_width = GetSize(sigH); - int actual_acc_width = GetSize(sigCD); +match ff + select ff->type.in($dff) + // DSP48E1 does not support clock inversion + select param(ff, \CLK_POLARITY).as_bool() - if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width)) + slice offset GetSize(port(ff, \D)) + index port(ff, \Q)[offset] === argQ[0] + + // Check that the rest of argQ is present + filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ) + filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ + + set ffoffset offset +endmatch + +code argQ argD +{ + if (clock != SigBit()) { + if (port(ff, \CLK) != clock) reject; - // If accumulator, check adder width and signedness - if (sigCD == sigH && (actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(addAB, \A_SIGNED).as_bool())) + if (param(ff, \CLK_POLARITY).as_bool() != clock_pol) reject; - - sigO = port(addAB, \Y); } + + SigSpec Q = port(ff, \Q); + dff = ff; + dffclock = port(ff, \CLK); + dffclock_pol = param(ff, \CLK_POLARITY).as_bool(); + dffD = argQ; + argD = port(ff, \D); + argQ = Q; + dffD.replace(argQ, argD); + // Only search for ffrstmux if dffD only + // has two (ff, ffrstmux) users + if (nusers(dffD) > 2) + argD = SigSpec(); +} endcode -match muxA - select muxA->type.in($mux) - index nusers(port(muxA, \A)) === 2 - index port(muxA, \A) === sigO - optional +match ffrstmux + if !argD.empty() + select ffrstmux->type.in($mux) + index port(ffrstmux, \Y) === argD + + choice BA {\B, \A} + // DSP48E1 only supports reset to zero + select port(ffrstmux, BA).is_fully_zero() + + define pol (BA == \B) + set ffrstpol pol + semioptional endmatch -match muxB - if !muxA - select muxB->type.in($mux) - index nusers(port(muxB, \B)) === 2 - index port(muxB, \B) === sigO - optional +code argD + if (ffrstmux) { + dffrstmux = ffrstmux; + dffrstpol = ffrstpol; + argD = port(ffrstmux, ffrstpol ? \A : \B); + dffD.replace(port(ffrstmux, \Y), argD); + + // Only search for ffcemux if argQ has at + // least 3 users (ff, , ffrstmux) and + // dffD only has two (ff, ffrstmux) + if (!(nusers(argQ) >= 3 && nusers(dffD) == 2)) + argD = SigSpec(); + } + else + dffrstmux = nullptr; +endcode + +match ffcemux + if !argD.empty() + select ffcemux->type.in($mux) + index port(ffcemux, \Y) === argD + choice AB {\A, \B} + index port(ffcemux, AB) === argQ + define pol (AB == \A) + set ffcepol pol + semioptional endmatch -code muxAB sigO - if (muxA) - muxAB = muxA; - else if (muxB) - muxAB = muxB; - if (muxAB) - sigO = port(muxAB, \Y); +code argD + if (ffcemux) { + dffcemux = ffcemux; + dffcepol = ffcepol; + argD = port(ffcemux, ffcepol ? \B : \A); + dffD.replace(port(ffcemux, \Y), argD); + } + else + dffcemux = nullptr; endcode -match ffO - // Ensure that register is not already used - if mul->type != \SB_MAC16 || (mul->parameters.at(\TOPOUTPUT_SELECT, 0).as_int() != 1 && mul->parameters.at(\BOTOUTPUT_SELECT, 0).as_int() != 1) - // Ensure that OLOADTOP/OLOADBOT is unused or zero - if mul->type != \SB_MAC16 || (mul->connections_.at(\OLOADTOP, State::S0).is_fully_zero() && mul->connections_.at(\OLOADBOT, State::S0).is_fully_zero()) - if nusers(sigO) == 2 - select ffO->type.in($dff) - filter GetSize(port(ffO, \D)) >= GetSize(sigO) - slice offset GetSize(port(ffO, \D)) - filter offset+GetSize(sigO) <= GetSize(port(ffO, \D)) && port(ffO, \D).extract(offset, GetSize(sigO)) == sigO - optional +// ####################### + +subpattern out_dffe +arg argD argQ clock clock_pol + +code + dff = nullptr; +endcode + +match ffcemux + select ffcemux->type.in($mux) + // ffcemux output must have two users: ffcemux and ff.D + select nusers(port(ffcemux, \Y)) == 2 + + choice AB {\A, \B} + // keep-last-value net must have at least three users: ffcemux, ff, downstream sink(s) + select nusers(port(ffcemux, AB)) >= 3 + + slice offset GetSize(port(ffcemux, \Y)) + define BA (AB == \A ? \B : \A) + index port(ffcemux, BA)[offset] === argD[0] + + // Check that the rest of argD is present + filter GetSize(BA) >= offset + GetSize(argD) + filter port(ffcemux, BA).extract(offset, GetSize(argD)) == argD + + set ffoffset offset + define pol (BA == \B) + set ffcepol pol + + semioptional endmatch -match ffO_lo - if !ffO && GetSize(sigO) > 16 - // Ensure that register is not already used - if mul->type != \SB_MAC16 || (mul->parameters.at(\TOPOUTPUT_SELECT, 0).as_int() != 1 && mul->parameters.at(\BOTOUTPUT_SELECT, 0).as_int() != 1) - // Ensure that OLOADTOP/OLOADBOT is unused or zero - if mul->type != \SB_MAC16 || (mul->connections_.at(\OLOADTOP, State::S0).is_fully_zero() && mul->connections_.at(\OLOADBOT, State::S0).is_fully_zero()) - if nusers(sigO.extract(0, 16)) == 2 - select ffO_lo->type.in($dff) - filter GetSize(port(ffO_lo, \D)) >= 16 - slice offset GetSize(port(ffO_lo, \D)) - filter offset+GetSize(sigO) <= GetSize(port(ffO_lo, \D)) && port(ffO_lo, \D).extract(offset, 16) == sigO.extract(0, 16) - optional +code argD argQ + dffcemux = ffcemux; + if (ffcemux) { + SigSpec BA = port(ffcemux, ffcepol ? \B : \A); + if (ffoffset + GetSize(argD) > GetSize(BA)) + reject; + for (int i = 1; i < GetSize(argD); i++) + if (BA[ffoffset+i] != argD[i]) + reject; + + SigSpec Y = port(ffcemux, \Y); + argQ = argD; + argD.replace(BA, Y); + argQ.replace(BA, port(ffcemux, ffcepol ? \A : \B)); + + dffcemux = ffcemux; + dffcepol = ffcepol; + } +endcode + +match ffrstmux + select ffrstmux->type.in($mux) + // ffrstmux output must have two users: ffrstmux and ff.D + select nusers(port(ffrstmux, \Y)) == 2 + + choice BA {\B, \A} + // DSP48E1 only supports reset to zero + select port(ffrstmux, BA).is_fully_zero() + + slice offset GetSize(port(ffrstmux, \Y)) + define AB (BA == \B ? \A : \B) + index port(ffrstmux, AB)[offset] === argD[0] + + // Check that offset is consistent + filter !ffcemux || ffoffset == offset + // Check that the rest of argD is present + filter GetSize(AB) >= offset + GetSize(argD) + filter port(ffrstmux, AB).extract(offset, GetSize(argD)) == argD + + set ffoffset offset + define pol (AB == \A) + set ffrstpol pol + + semioptional endmatch -code ffO clock clock_pol sigO sigCD cd_signed - if (ffO_lo) { - log_assert(!ffO); - ffO = ffO_lo; +code argD argQ + dffrstmux = ffrstmux; + if (ffrstmux) { + SigSpec AB = port(ffrstmux, ffrstpol ? \A : \B); + SigSpec Y = port(ffrstmux, \Y); + argD.replace(AB, Y); + + dffrstmux = ffrstmux; + dffrstpol = ffrstpol; } - if (ffO) { - for (auto b : port(ffO, \Q)) - if (b.wire->get_bool_attribute(\keep)) - reject; +endcode - SigBit c = port(ffO, \CLK).as_bit(); - bool cp = param(ffO, \CLK_POLARITY).as_bool(); +match ff + select ff->type.in($dff) + // DSP48E1 does not support clock inversion + select param(ff, \CLK_POLARITY).as_bool() - if (clock != SigBit() && (c != clock || cp != clock_pol)) - reject; + slice offset GetSize(port(ff, \D)) + index port(ff, \D)[offset] === argD[0] - clock = c; - clock_pol = cp; + // Check that offset is consistent + filter (!ffcemux && !ffrstmux) || ffoffset == offset + // Check that the rest of argD is present + filter GetSize(port(ff, \D)) >= offset + GetSize(argD) + filter port(ff, \D).extract(offset, GetSize(argD)) == argD + // Check that FF.Q is connected to CE-mux + filter !ffcemux || port(ff, \Q).extract(offset, GetSize(argQ)) == argQ - sigO.replace(port(ffO, \D), port(ffO, \Q)); + set ffoffset offset - // Loading value into output register is not - // supported unless using accumulator - if (muxAB) { - if (sigCD != sigO) + semioptional +endmatch + +code argQ + if (ff) { + if (clock != SigBit()) { + if (port(ff, \CLK) != clock) reject; - if (muxA) - sigCD = port(muxAB, \B); - else if (muxB) - sigCD = port(muxAB, \A); - else log_abort(); + if (param(ff, \CLK_POLARITY).as_bool() != clock_pol) + reject; + } - cd_signed = addAB && param(addAB, \A_SIGNED).as_bool() && param(addAB, \B_SIGNED).as_bool(); + SigSpec D = port(ff, \D); + SigSpec Q = port(ff, \Q); + if (!ffcemux) { + argQ = argD; + argQ.replace(D, Q); } - } - sigCD.extend_u0(32, cd_signed); -endcode -code - accept; + for (auto c : argQ.chunks()) { + if (c.wire->get_bool_attribute(\keep)) + reject; + Const init = c.wire->attributes.at(\init, State::Sx); + if (!init.is_fully_undef() && !init.is_fully_zero()) + reject; + } + + dff = ff; + dffQ = argQ; + dffclock = port(ff, \CLK); + dffclock_pol = param(ff, \CLK_POLARITY).as_bool(); + } + // No enable/reset mux possible without flop + else if (dffcemux || dffrstmux) + reject; endcode -- cgit v1.2.3 From 2766465a2bf73fcd490a160a124b6167851f2d10 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 19 Sep 2019 12:14:33 -0700 Subject: Add support for SB_MAC16 CD and H registers --- passes/pmgen/ice40_dsp.cc | 15 +++++++--- passes/pmgen/ice40_dsp.pmg | 71 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 73 insertions(+), 13 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 4132857d6..7592593a6 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -33,8 +33,10 @@ void create_ice40_dsp(ice40_dsp_pm &pm) log("\n"); log("ffA: %s %s %s\n", log_id(st.ffA, "--"), log_id(st.ffAcemux, "--"), log_id(st.ffArstmux, "--")); log("ffB: %s %s %s\n", log_id(st.ffB, "--"), log_id(st.ffBcemux, "--"), log_id(st.ffBrstmux, "--")); + log("ffCD: %s %s %s\n", log_id(st.ffCD, "--"), log_id(st.ffCDcemux, "--"), log_id(st.ffCDrstmux, "--")); log("mul: %s\n", log_id(st.mul, "--")); log("ffFJKG: %s n/a %s\n", log_id(st.ffFJKG, "--"), log_id(st.ffFJKGrstmux, "--")); + log("ffH: %s n/a %s\n", log_id(st.ffH, "--"), log_id(st.ffHrstmux, "--")); log("add: %s\n", log_id(st.add, "--")); log("mux: %s\n", log_id(st.mux, "--")); log("ffO: %s\n", log_id(st.ffO, "--")); @@ -93,6 +95,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam("\\A_REG", st.ffA ? State::S1 : State::S0); cell->setParam("\\B_REG", st.ffB ? State::S1 : State::S0); + cell->setParam("\\C_REG", st.ffCD ? State::S1 : State::S0); + cell->setParam("\\D_REG", st.ffCD ? State::S1 : State::S0); cell->setPort("\\AHOLD", State::S0); cell->setPort("\\BHOLD", State::S0); @@ -116,9 +120,15 @@ void create_ice40_dsp(ice40_dsp_pm &pm) if (st.ffB) log(" ffB:%s", log_id(st.ffB)); + if (st.ffCD) + log(" ffCD:%s", log_id(st.ffCD)); + if (st.ffFJKG) log(" ffFJKG:%s", log_id(st.ffFJKG)); + if (st.ffH) + log(" ffH:%s", log_id(st.ffH)); + if (st.ffO) log(" ffO:%s", log_id(st.ffO)); @@ -196,13 +206,10 @@ void create_ice40_dsp(ice40_dsp_pm &pm) // SB_MAC16 Remaining Parameters - cell->setParam("\\C_REG", State::S0); - cell->setParam("\\D_REG", State::S0); - cell->setParam("\\TOP_8x8_MULT_REG", st.ffFJKG ? State::S1 : State::S0); cell->setParam("\\BOT_8x8_MULT_REG", st.ffFJKG ? State::S1 : State::S0); cell->setParam("\\PIPELINE_16x16_MULT_REG1", st.ffFJKG ? State::S1 : State::S0); - cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0); + cell->setParam("\\PIPELINE_16x16_MULT_REG2", st.ffH ? State::S1 : State::S0); cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2)); cell->setParam("\\TOPADDSUB_UPPERINPUT", accum ? State::S0 : State::S1); diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 22267aea7..532995da7 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -7,10 +7,10 @@ state add mux state addAB muxAB state ffAcepol ffBcepol ffCDcepol ffOcepol -state ffArstpol ffBrstpol ffCDrstpol ffFJKGrstpol ffOrstpol +state ffArstpol ffBrstpol ffCDrstpol ffOrstpol state ffA ffAcemux ffArstmux ffB ffBcemux ffBrstmux ffCD ffCDcemux ffCDrstmux -state ffFJKG ffFJKGrstmux ffO ffOcemux ffOrstmux +state ffFJKG ffFJKGrstmux ffH ffHrstmux ffO ffOcemux ffOrstmux // subpattern state argQ argD @@ -105,20 +105,18 @@ code argQ ffB ffBcemux ffBrstmux ffBcepol ffBrstpol sigB clock clock_pol } endcode -code argD ffFJKG ffFJKGrstmux ffFJKGrstpol sigH sigO clock clock_pol +code argD ffFJKG ffFJKGrstmux sigH sigO clock clock_pol if (nusers(sigH) == 2 && (mul->type != \SB_MAC16 || - (!param(mul, \TOP_8x8_MULT_REG).as_bool() && !param(mul, \BOT_8x8_MULT_REG).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG2).as_bool()))) { + (!param(mul, \TOP_8x8_MULT_REG).as_bool() && !param(mul, \BOT_8x8_MULT_REG).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool()))) { argD = sigH; subpattern(out_dffe); if (dff) { ffFJKG = dff; clock = dffclock; clock_pol = dffclock_pol; - if (dffrstmux) { + if (dffrstmux) ffFJKGrstmux = dffrstmux; - ffFJKGrstpol = dffrstpol; - } // F/J/K/G do not have a CE-like (hold) input if (dffcemux) reject; @@ -132,13 +130,43 @@ code argD ffFJKG ffFJKGrstmux ffFJKGrstpol sigH sigO clock clock_pol if (ffArstmux) { if (port(ffArstmux, \S) != port(ffFJKGrstmux, \S)) reject; - if (ffArstpol != ffFJKGrstpol) + if (ffArstpol != dffrstpol) reject; } if (ffBrstmux) { if (port(ffBrstmux, \S) != port(ffFJKGrstmux, \S)) reject; - if (ffBrstpol != ffFJKGrstpol) + if (ffBrstpol != dffrstpol) + reject; + } + + sigH = dffQ; + } + } +endcode + +code argD ffH ffHrstmux sigH sigO clock clock_pol + if (nusers(sigH) == 2 && + (mul->type != \SB_MAC16 || !param(mul, \PIPELINE_16x16_MULT_REG2).as_bool())) { + argD = sigH; + subpattern(out_dffe); + if (dff) { + ffH = dff; + clock = dffclock; + clock_pol = dffclock_pol; + if (dffrstmux) + ffHrstmux = dffrstmux; + // H does not have a CE-like (hold) input + if (dffcemux) + reject; + + // Reset signal of H (IRSTBOT) shared with B + if ((ffBrstmux != NULL) != (ffHrstmux != NULL)) + reject; + if (ffBrstmux) { + if (port(ffBrstmux, \S) != port(ffHrstmux, \S)) + reject; + if (ffBrstpol != dffrstpol) reject; } @@ -244,6 +272,31 @@ code argD ffO ffOcemux ffOrstmux ffOcepol ffOrstpol sigO sigCD clock clock_pol c cd_signed = add && param(add, \A_SIGNED).as_bool() && param(add, \B_SIGNED).as_bool(); } } +endcode + +code argQ ffCD ffCDcemux ffCDrstmux ffCDcepol ffCDrstpol sigCD clock clock_pol + if (!sigCD.empty() && + (mul->type != \SB_MAC16 || (!param(mul, \C_REG).as_bool() && !param(mul, \D_REG).as_bool()))) { + argQ = sigCD; + subpattern(in_dffe); + if (dff) { + ffCD = dff; + clock = dffclock; + clock_pol = dffclock_pol; + if (dffrstmux) { + ffCDrstmux = dffrstmux; + ffCDrstpol = dffrstpol; + } + if (dffcemux) { + ffCDcemux = dffcemux; + ffCDcepol = dffcepol; + } + sigCD = dffD; + } + } +endcode + +code sigCD sigCD.extend_u0(32, cd_signed); endcode -- cgit v1.2.3 From 429c9852cee3bd7f133944044c74c26b8f6a4209 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 19 Sep 2019 14:02:55 -0700 Subject: Add HOLD/RST support for SB_MAC16 --- passes/pmgen/ice40_dsp.cc | 63 +++++++++++++++++------ passes/pmgen/ice40_dsp.pmg | 122 +++++++++++++++++++++++++-------------------- 2 files changed, 116 insertions(+), 69 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 7592593a6..f3cc83699 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -33,13 +33,13 @@ void create_ice40_dsp(ice40_dsp_pm &pm) log("\n"); log("ffA: %s %s %s\n", log_id(st.ffA, "--"), log_id(st.ffAcemux, "--"), log_id(st.ffArstmux, "--")); log("ffB: %s %s %s\n", log_id(st.ffB, "--"), log_id(st.ffBcemux, "--"), log_id(st.ffBrstmux, "--")); - log("ffCD: %s %s %s\n", log_id(st.ffCD, "--"), log_id(st.ffCDcemux, "--"), log_id(st.ffCDrstmux, "--")); + log("ffCD: %s %s\n", log_id(st.ffCD, "--"), log_id(st.ffCDcemux, "--")); log("mul: %s\n", log_id(st.mul, "--")); - log("ffFJKG: %s n/a %s\n", log_id(st.ffFJKG, "--"), log_id(st.ffFJKGrstmux, "--")); - log("ffH: %s n/a %s\n", log_id(st.ffH, "--"), log_id(st.ffHrstmux, "--")); + log("ffFJKG: %s\n", log_id(st.ffFJKG, "--")); + log("ffH: %s\n", log_id(st.ffH, "--")); log("add: %s\n", log_id(st.add, "--")); log("mux: %s\n", log_id(st.mux, "--")); - log("ffO: %s\n", log_id(st.ffO, "--")); + log("ffO: %s %s %s\n", log_id(st.ffO, "--"), log_id(st.ffOcemux, "--"), log_id(st.ffOrstmux, "--")); #endif log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(st.mul)); @@ -98,13 +98,35 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam("\\C_REG", st.ffCD ? State::S1 : State::S0); cell->setParam("\\D_REG", st.ffCD ? State::S1 : State::S0); - cell->setPort("\\AHOLD", State::S0); - cell->setPort("\\BHOLD", State::S0); - cell->setPort("\\CHOLD", State::S0); - cell->setPort("\\DHOLD", State::S0); - - cell->setPort("\\IRSTTOP", State::S0); - cell->setPort("\\IRSTBOT", State::S0); + SigSpec AHOLD, BHOLD, CDHOLD; + if (st.ffAcemux) + AHOLD = st.ffAcepol ? pm.module->Not(NEW_ID, st.ffAcemux->getPort("\\S")) : st.ffAcemux->getPort("\\S"); + else + AHOLD = State::S0; + if (st.ffBcemux) + BHOLD = st.ffBcepol ? pm.module->Not(NEW_ID, st.ffBcemux->getPort("\\S")) : st.ffBcemux->getPort("\\S"); + else + BHOLD = State::S0; + if (st.ffCDcemux) + CDHOLD = st.ffCDcepol ? pm.module->Not(NEW_ID, st.ffCDcemux->getPort("\\S")) : st.ffCDcemux->getPort("\\S"); + else + CDHOLD = State::S0; + cell->setPort("\\AHOLD", AHOLD); + cell->setPort("\\BHOLD", BHOLD); + cell->setPort("\\CHOLD", CDHOLD); + cell->setPort("\\DHOLD", CDHOLD); + + SigSpec IRSTTOP, IRSTBOT; + if (st.ffArstmux) + IRSTTOP = st.ffArstpol ? st.ffArstmux->getPort("\\S") : pm.module->Not(NEW_ID, st.ffArstmux->getPort("\\S")); + else + IRSTTOP = State::S0; + if (st.ffBrstmux) + IRSTBOT = st.ffBrstpol ? st.ffBrstmux->getPort("\\S") : pm.module->Not(NEW_ID, st.ffBrstmux->getPort("\\S")); + else + IRSTBOT = State::S0; + cell->setPort("\\IRSTTOP", IRSTTOP); + cell->setPort("\\IRSTBOT", IRSTBOT); if (st.clock != SigBit()) { @@ -187,11 +209,21 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setPort("\\ADDSUBBOT", State::S0); } - cell->setPort("\\ORSTTOP", State::S0); - cell->setPort("\\ORSTBOT", State::S0); + SigSpec OHOLD; + if (st.ffOcemux) + OHOLD = st.ffOcemux ? pm.module->Not(NEW_ID, st.ffOcemux->getPort("\\S")) : st.ffOcemux->getPort("\\S"); + else + OHOLD = State::S0; + cell->setPort("\\OHOLDTOP", OHOLD); + cell->setPort("\\OHOLDBOT", OHOLD); - cell->setPort("\\OHOLDTOP", State::S0); - cell->setPort("\\OHOLDBOT", State::S0); + SigSpec ORST; + if (st.ffOrstmux) + ORST = st.ffOrstmux ? st.ffOrstmux->getPort("\\S") : pm.module->Not(NEW_ID, st.ffOrstmux->getPort("\\S")); + else + ORST = State::S0; + cell->setPort("\\ORSTTOP", ORST); + cell->setPort("\\ORSTBOT", ORST); SigSpec acc_reset = State::S0; if (st.mux) { @@ -200,7 +232,6 @@ void create_ice40_dsp(ice40_dsp_pm &pm) else acc_reset = pm.module->Not(NEW_ID, st.mux->getPort("\\S")); } - cell->setPort("\\OLOADTOP", acc_reset); cell->setPort("\\OLOADBOT", acc_reset); diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 532995da7..01e344767 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -9,8 +9,8 @@ state addAB muxAB state ffAcepol ffBcepol ffCDcepol ffOcepol state ffArstpol ffBrstpol ffCDrstpol ffOrstpol -state ffA ffAcemux ffArstmux ffB ffBcemux ffBrstmux ffCD ffCDcemux ffCDrstmux -state ffFJKG ffFJKGrstmux ffH ffHrstmux ffO ffOcemux ffOrstmux +state ffA ffAcemux ffArstmux ffB ffBcemux ffBrstmux ffCD ffCDcemux +state ffFJKG ffH ffO ffOcemux ffOrstmux // subpattern state argQ argD @@ -105,75 +105,79 @@ code argQ ffB ffBcemux ffBrstmux ffBcepol ffBrstpol sigB clock clock_pol } endcode -code argD ffFJKG ffFJKGrstmux sigH sigO clock clock_pol +code argD ffFJKG sigH sigO clock clock_pol if (nusers(sigH) == 2 && (mul->type != \SB_MAC16 || (!param(mul, \TOP_8x8_MULT_REG).as_bool() && !param(mul, \BOT_8x8_MULT_REG).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool()))) { argD = sigH; subpattern(out_dffe); if (dff) { - ffFJKG = dff; - clock = dffclock; - clock_pol = dffclock_pol; - if (dffrstmux) - ffFJKGrstmux = dffrstmux; // F/J/K/G do not have a CE-like (hold) input if (dffcemux) - reject; + goto reject_ffFJKG; // Reset signal of F/J (IRSTTOP) and K/G (IRSTBOT) // shared with A and B - if ((ffArstmux != NULL) != (ffFJKGrstmux != NULL)) - reject; - if ((ffBrstmux != NULL) != (ffFJKGrstmux != NULL)) - reject; + if ((ffArstmux != NULL) != (dffrstmux != NULL)) + goto reject_ffFJKG; + if ((ffBrstmux != NULL) != (dffrstmux != NULL)) + goto reject_ffFJKG; if (ffArstmux) { - if (port(ffArstmux, \S) != port(ffFJKGrstmux, \S)) - reject; + if (port(ffArstmux, \S) != port(dffrstmux, \S)) + goto reject_ffFJKG; if (ffArstpol != dffrstpol) - reject; + goto reject_ffFJKG; } if (ffBrstmux) { - if (port(ffBrstmux, \S) != port(ffFJKGrstmux, \S)) - reject; + if (port(ffBrstmux, \S) != port(dffrstmux, \S)) + goto reject_ffFJKG; if (ffBrstpol != dffrstpol) - reject; + goto reject_ffFJKG; } + ffFJKG = dff; + clock = dffclock; + clock_pol = dffclock_pol; sigH = dffQ; } } + + if (0) { +reject_ffFJKG: ; + } endcode -code argD ffH ffHrstmux sigH sigO clock clock_pol - if (nusers(sigH) == 2 && +code argD ffH sigH sigO clock clock_pol + if (ffFJKG && nusers(sigH) == 2 && (mul->type != \SB_MAC16 || !param(mul, \PIPELINE_16x16_MULT_REG2).as_bool())) { argD = sigH; subpattern(out_dffe); if (dff) { - ffH = dff; - clock = dffclock; - clock_pol = dffclock_pol; - if (dffrstmux) - ffHrstmux = dffrstmux; // H does not have a CE-like (hold) input if (dffcemux) - reject; + goto reject_ffH; // Reset signal of H (IRSTBOT) shared with B - if ((ffBrstmux != NULL) != (ffHrstmux != NULL)) - reject; + if ((ffBrstmux != NULL) != (dffrstmux != NULL)) + goto reject_ffH; if (ffBrstmux) { - if (port(ffBrstmux, \S) != port(ffHrstmux, \S)) - reject; + if (port(ffBrstmux, \S) != port(dffrstmux, \S)) + goto reject_ffH; if (ffBrstpol != dffrstpol) - reject; + goto reject_ffH; } + ffH = dff; + clock = dffclock; + clock_pol = dffclock_pol; sigH = dffQ; } } + if (0) { +reject_ffH: ; + } + sigO = sigH; endcode @@ -274,26 +278,46 @@ code argD ffO ffOcemux ffOrstmux ffOcepol ffOrstpol sigO sigCD clock clock_pol c } endcode -code argQ ffCD ffCDcemux ffCDrstmux ffCDcepol ffCDrstpol sigCD clock clock_pol +code argQ ffCD ffCDcemux ffCDcepol ffCDrstpol sigCD clock clock_pol if (!sigCD.empty() && (mul->type != \SB_MAC16 || (!param(mul, \C_REG).as_bool() && !param(mul, \D_REG).as_bool()))) { argQ = sigCD; subpattern(in_dffe); if (dff) { - ffCD = dff; - clock = dffclock; - clock_pol = dffclock_pol; - if (dffrstmux) { - ffCDrstmux = dffrstmux; - ffCDrstpol = dffrstpol; - } if (dffcemux) { ffCDcemux = dffcemux; ffCDcepol = dffcepol; } + + // Reset signal of C (IRSTTOP) and D (IRSTBOT) + // shared with A and B + if ((ffArstmux != NULL) != (dffrstmux != NULL)) + goto reject_ffCD; + if ((ffBrstmux != NULL) != (dffrstmux != NULL)) + goto reject_ffCD; + if (ffArstmux) { + if (port(ffArstmux, \S) != port(dffrstmux, \S)) + goto reject_ffCD; + if (ffArstpol != dffrstpol) + goto reject_ffCD; + } + if (ffBrstmux) { + if (port(ffBrstmux, \S) != port(dffrstmux, \S)) + goto reject_ffCD; + if (ffBrstpol != dffrstpol) + goto reject_ffCD; + } + + ffCD = dff; + clock = dffclock; + clock_pol = dffclock_pol; sigCD = dffD; } } + + if (0) { +reject_ffCD: ; + } endcode code sigCD @@ -418,6 +442,9 @@ arg argD argQ clock clock_pol code dff = nullptr; + for (auto c : argD.chunks()) + if (c.wire->get_bool_attribute(\keep)) + reject; endcode match ffcemux @@ -434,7 +461,7 @@ match ffcemux index port(ffcemux, BA)[offset] === argD[0] // Check that the rest of argD is present - filter GetSize(BA) >= offset + GetSize(argD) + filter GetSize(port(ffcemux, BA)) >= offset + GetSize(argD) filter port(ffcemux, BA).extract(offset, GetSize(argD)) == argD set ffoffset offset @@ -448,12 +475,6 @@ code argD argQ dffcemux = ffcemux; if (ffcemux) { SigSpec BA = port(ffcemux, ffcepol ? \B : \A); - if (ffoffset + GetSize(argD) > GetSize(BA)) - reject; - for (int i = 1; i < GetSize(argD); i++) - if (BA[ffoffset+i] != argD[i]) - reject; - SigSpec Y = port(ffcemux, \Y); argQ = argD; argD.replace(BA, Y); @@ -480,7 +501,7 @@ match ffrstmux // Check that offset is consistent filter !ffcemux || ffoffset == offset // Check that the rest of argD is present - filter GetSize(AB) >= offset + GetSize(argD) + filter GetSize(port(ffrstmux, AB)) >= offset + GetSize(argD) filter port(ffrstmux, AB).extract(offset, GetSize(argD)) == argD set ffoffset offset @@ -519,8 +540,6 @@ match ff filter !ffcemux || port(ff, \Q).extract(offset, GetSize(argQ)) == argQ set ffoffset offset - - semioptional endmatch code argQ @@ -531,7 +550,6 @@ code argQ if (param(ff, \CLK_POLARITY).as_bool() != clock_pol) reject; } - SigSpec D = port(ff, \D); SigSpec Q = port(ff, \Q); if (!ffcemux) { @@ -540,8 +558,6 @@ code argQ } for (auto c : argQ.chunks()) { - if (c.wire->get_bool_attribute(\keep)) - reject; Const init = c.wire->attributes.at(\init, State::Sx); if (!init.is_fully_undef() && !init.is_fully_zero()) reject; -- cgit v1.2.3 From 1a0f7ed09c5c14242aa89d572f617ad96ed42fa1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 19 Sep 2019 14:27:25 -0700 Subject: Refactor ce{mux,pol} -> hold{mux,pol} --- passes/pmgen/ice40_dsp.cc | 26 ++++----- passes/pmgen/ice40_dsp.pmg | 128 ++++++++++++++++++++++----------------------- 2 files changed, 77 insertions(+), 77 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index f3cc83699..b119b6b7c 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -31,15 +31,15 @@ void create_ice40_dsp(ice40_dsp_pm &pm) #if 1 log("\n"); - log("ffA: %s %s %s\n", log_id(st.ffA, "--"), log_id(st.ffAcemux, "--"), log_id(st.ffArstmux, "--")); - log("ffB: %s %s %s\n", log_id(st.ffB, "--"), log_id(st.ffBcemux, "--"), log_id(st.ffBrstmux, "--")); - log("ffCD: %s %s\n", log_id(st.ffCD, "--"), log_id(st.ffCDcemux, "--")); + log("ffA: %s %s %s\n", log_id(st.ffA, "--"), log_id(st.ffAholdmux, "--"), log_id(st.ffArstmux, "--")); + log("ffB: %s %s %s\n", log_id(st.ffB, "--"), log_id(st.ffBholdmux, "--"), log_id(st.ffBrstmux, "--")); + log("ffCD: %s %s\n", log_id(st.ffCD, "--"), log_id(st.ffCDholdmux, "--")); log("mul: %s\n", log_id(st.mul, "--")); log("ffFJKG: %s\n", log_id(st.ffFJKG, "--")); log("ffH: %s\n", log_id(st.ffH, "--")); log("add: %s\n", log_id(st.add, "--")); log("mux: %s\n", log_id(st.mux, "--")); - log("ffO: %s %s %s\n", log_id(st.ffO, "--"), log_id(st.ffOcemux, "--"), log_id(st.ffOrstmux, "--")); + log("ffO: %s %s %s\n", log_id(st.ffO, "--"), log_id(st.ffOholdmux, "--"), log_id(st.ffOrstmux, "--")); #endif log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(st.mul)); @@ -99,16 +99,16 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam("\\D_REG", st.ffCD ? State::S1 : State::S0); SigSpec AHOLD, BHOLD, CDHOLD; - if (st.ffAcemux) - AHOLD = st.ffAcepol ? pm.module->Not(NEW_ID, st.ffAcemux->getPort("\\S")) : st.ffAcemux->getPort("\\S"); + if (st.ffAholdmux) + AHOLD = st.ffAholdpol ? st.ffAholdmux->getPort("\\S") : pm.module->Not(NEW_ID, st.ffAholdmux->getPort("\\S")); else AHOLD = State::S0; - if (st.ffBcemux) - BHOLD = st.ffBcepol ? pm.module->Not(NEW_ID, st.ffBcemux->getPort("\\S")) : st.ffBcemux->getPort("\\S"); + if (st.ffBholdmux) + BHOLD = st.ffBholdpol ? st.ffBholdmux->getPort("\\S") : pm.module->Not(NEW_ID, st.ffBholdmux->getPort("\\S")); else BHOLD = State::S0; - if (st.ffCDcemux) - CDHOLD = st.ffCDcepol ? pm.module->Not(NEW_ID, st.ffCDcemux->getPort("\\S")) : st.ffCDcemux->getPort("\\S"); + if (st.ffCDholdmux) + CDHOLD = st.ffCDholdpol ? st.ffCDholdmux->getPort("\\S") : pm.module->Not(NEW_ID, st.ffCDholdmux->getPort("\\S")); else CDHOLD = State::S0; cell->setPort("\\AHOLD", AHOLD); @@ -210,8 +210,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm) } SigSpec OHOLD; - if (st.ffOcemux) - OHOLD = st.ffOcemux ? pm.module->Not(NEW_ID, st.ffOcemux->getPort("\\S")) : st.ffOcemux->getPort("\\S"); + if (st.ffOholdmux) + OHOLD = st.ffOholdpol ? st.ffOholdmux->getPort("\\S") : pm.module->Not(NEW_ID, st.ffOholdmux->getPort("\\S")); else OHOLD = State::S0; cell->setPort("\\OHOLDTOP", OHOLD); @@ -219,7 +219,7 @@ void create_ice40_dsp(ice40_dsp_pm &pm) SigSpec ORST; if (st.ffOrstmux) - ORST = st.ffOrstmux ? st.ffOrstmux->getPort("\\S") : pm.module->Not(NEW_ID, st.ffOrstmux->getPort("\\S")); + ORST = st.ffOrstpol ? st.ffOrstmux->getPort("\\S") : pm.module->Not(NEW_ID, st.ffOrstmux->getPort("\\S")); else ORST = State::S0; cell->setPort("\\ORSTTOP", ORST); diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 01e344767..aa081241d 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -6,20 +6,20 @@ state sigA sigB sigCD sigH sigO state add mux state addAB muxAB -state ffAcepol ffBcepol ffCDcepol ffOcepol +state ffAholdpol ffBholdpol ffCDholdpol ffOholdpol state ffArstpol ffBrstpol ffCDrstpol ffOrstpol -state ffA ffAcemux ffArstmux ffB ffBcemux ffBrstmux ffCD ffCDcemux -state ffFJKG ffH ffO ffOcemux ffOrstmux +state ffA ffAholdmux ffArstmux ffB ffBholdmux ffBrstmux ffCD ffCDholdmux +state ffFJKG ffH ffO ffOholdmux ffOrstmux // subpattern state argQ argD -state ffcepol ffrstpol +state ffholdpol ffrstpol state ffoffset udata dffD dffQ udata dffclock -udata dff dffcemux dffrstmux -udata dffcepol dffrstpol dffclock_pol +udata dff dffholdmux dffrstmux +udata dffholdpol dffrstpol dffclock_pol match mul select mul->type.in($mul, \SB_MAC16) @@ -63,7 +63,7 @@ code sigA sigB sigH log_assert(nusers(O.extract_end(i)) <= 1); endcode -code argQ ffA ffAcemux ffArstmux ffAcepol ffArstpol sigA clock clock_pol +code argQ ffA ffAholdmux ffArstmux ffAholdpol ffArstpol sigA clock clock_pol if (mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool()) { argQ = sigA; subpattern(in_dffe); @@ -75,16 +75,16 @@ code argQ ffA ffAcemux ffArstmux ffAcepol ffArstpol sigA clock clock_pol ffArstmux = dffrstmux; ffArstpol = dffrstpol; } - if (dffcemux) { - ffAcemux = dffcemux; - ffAcepol = dffcepol; + if (dffholdmux) { + ffAholdmux = dffholdmux; + ffAholdpol = dffholdpol; } sigA = dffD; } } endcode -code argQ ffB ffBcemux ffBrstmux ffBcepol ffBrstpol sigB clock clock_pol +code argQ ffB ffBholdmux ffBrstmux ffBholdpol ffBrstpol sigB clock clock_pol if (mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool()) { argQ = sigB; subpattern(in_dffe); @@ -96,9 +96,9 @@ code argQ ffB ffBcemux ffBrstmux ffBcepol ffBrstpol sigB clock clock_pol ffBrstmux = dffrstmux; ffBrstpol = dffrstpol; } - if (dffcemux) { - ffBcemux = dffcemux; - ffBcepol = dffcepol; + if (dffholdmux) { + ffBholdmux = dffholdmux; + ffBholdpol = dffholdpol; } sigB = dffD; } @@ -113,7 +113,7 @@ code argD ffFJKG sigH sigO clock clock_pol subpattern(out_dffe); if (dff) { // F/J/K/G do not have a CE-like (hold) input - if (dffcemux) + if (dffholdmux) goto reject_ffFJKG; // Reset signal of F/J (IRSTTOP) and K/G (IRSTBOT) @@ -154,7 +154,7 @@ code argD ffH sigH sigO clock clock_pol subpattern(out_dffe); if (dff) { // H does not have a CE-like (hold) input - if (dffcemux) + if (dffholdmux) goto reject_ffH; // Reset signal of H (IRSTBOT) shared with B @@ -226,7 +226,7 @@ code sigO sigO = port(mux, \Y); endcode -code argD ffO ffOcemux ffOrstmux ffOcepol ffOrstpol sigO sigCD clock clock_pol cd_signed o_lo +code argD ffO ffOholdmux ffOrstmux ffOholdpol ffOrstpol sigO sigCD clock clock_pol cd_signed o_lo if (mul->type != \SB_MAC16 || // Ensure that register is not already used ((mul->parameters.at(\TOPOUTPUT_SELECT, 0).as_int() != 1 && mul->parameters.at(\BOTOUTPUT_SELECT, 0).as_int() != 1) && @@ -258,9 +258,9 @@ code argD ffO ffOcemux ffOrstmux ffOcepol ffOrstpol sigO sigCD clock clock_pol c ffOrstmux = dffrstmux; ffOrstpol = dffrstpol; } - if (dffcemux) { - ffOcemux = dffcemux; - ffOcepol = dffcepol; + if (dffholdmux) { + ffOholdmux = dffholdmux; + ffOholdpol = dffholdpol; } sigO.replace(sigO.extract(0, GetSize(dffQ)), dffQ); @@ -278,15 +278,15 @@ code argD ffO ffOcemux ffOrstmux ffOcepol ffOrstpol sigO sigCD clock clock_pol c } endcode -code argQ ffCD ffCDcemux ffCDcepol ffCDrstpol sigCD clock clock_pol +code argQ ffCD ffCDholdmux ffCDholdpol ffCDrstpol sigCD clock clock_pol if (!sigCD.empty() && (mul->type != \SB_MAC16 || (!param(mul, \C_REG).as_bool() && !param(mul, \D_REG).as_bool()))) { argQ = sigCD; subpattern(in_dffe); if (dff) { - if (dffcemux) { - ffCDcemux = dffcemux; - ffCDcepol = dffcepol; + if (dffholdmux) { + ffCDholdmux = dffholdmux; + ffCDholdpol = dffholdpol; } // Reset signal of C (IRSTTOP) and D (IRSTBOT) @@ -403,7 +403,7 @@ code argD argD = port(ffrstmux, ffrstpol ? \A : \B); dffD.replace(port(ffrstmux, \Y), argD); - // Only search for ffcemux if argQ has at + // Only search for ffholdmux if argQ has at // least 3 users (ff, , ffrstmux) and // dffD only has two (ff, ffrstmux) if (!(nusers(argQ) >= 3 && nusers(dffD) == 2)) @@ -413,26 +413,26 @@ code argD dffrstmux = nullptr; endcode -match ffcemux +match ffholdmux if !argD.empty() - select ffcemux->type.in($mux) - index port(ffcemux, \Y) === argD - choice AB {\A, \B} - index port(ffcemux, AB) === argQ - define pol (AB == \A) - set ffcepol pol + select ffholdmux->type.in($mux) + index port(ffholdmux, \Y) === argD + choice BA {\B, \A} + index port(ffholdmux, BA) === argQ + define pol (BA == \B) + set ffholdpol pol semioptional endmatch code argD - if (ffcemux) { - dffcemux = ffcemux; - dffcepol = ffcepol; - argD = port(ffcemux, ffcepol ? \B : \A); - dffD.replace(port(ffcemux, \Y), argD); + if (ffholdmux) { + dffholdmux = ffholdmux; + dffholdpol = ffholdpol; + argD = port(ffholdmux, ffholdpol ? \A : \B); + dffD.replace(port(ffholdmux, \Y), argD); } else - dffcemux = nullptr; + dffholdmux = nullptr; endcode // ####################### @@ -447,41 +447,41 @@ code reject; endcode -match ffcemux - select ffcemux->type.in($mux) - // ffcemux output must have two users: ffcemux and ff.D - select nusers(port(ffcemux, \Y)) == 2 +match ffholdmux + select ffholdmux->type.in($mux) + // ffholdmux output must have two users: ffholdmux and ff.D + select nusers(port(ffholdmux, \Y)) == 2 - choice AB {\A, \B} - // keep-last-value net must have at least three users: ffcemux, ff, downstream sink(s) - select nusers(port(ffcemux, AB)) >= 3 + choice BA {\B, \A} + // keep-last-value net must have at least three users: ffholdmux, ff, downstream sink(s) + select nusers(port(ffholdmux, BA)) >= 3 - slice offset GetSize(port(ffcemux, \Y)) - define BA (AB == \A ? \B : \A) - index port(ffcemux, BA)[offset] === argD[0] + slice offset GetSize(port(ffholdmux, \Y)) + define AB (BA == \B ? \A : \B) + index port(ffholdmux, AB)[offset] === argD[0] // Check that the rest of argD is present - filter GetSize(port(ffcemux, BA)) >= offset + GetSize(argD) - filter port(ffcemux, BA).extract(offset, GetSize(argD)) == argD + filter GetSize(port(ffholdmux, AB)) >= offset + GetSize(argD) + filter port(ffholdmux, AB).extract(offset, GetSize(argD)) == argD set ffoffset offset define pol (BA == \B) - set ffcepol pol + set ffholdpol pol semioptional endmatch code argD argQ - dffcemux = ffcemux; - if (ffcemux) { - SigSpec BA = port(ffcemux, ffcepol ? \B : \A); - SigSpec Y = port(ffcemux, \Y); + dffholdmux = ffholdmux; + if (ffholdmux) { + SigSpec AB = port(ffholdmux, ffholdpol ? \A : \B); + SigSpec Y = port(ffholdmux, \Y); argQ = argD; - argD.replace(BA, Y); - argQ.replace(BA, port(ffcemux, ffcepol ? \A : \B)); + argD.replace(AB, Y); + argQ.replace(AB, port(ffholdmux, ffholdpol ? \B : \A)); - dffcemux = ffcemux; - dffcepol = ffcepol; + dffholdmux = ffholdmux; + dffholdpol = ffholdpol; } endcode @@ -499,7 +499,7 @@ match ffrstmux index port(ffrstmux, AB)[offset] === argD[0] // Check that offset is consistent - filter !ffcemux || ffoffset == offset + filter !ffholdmux || ffoffset == offset // Check that the rest of argD is present filter GetSize(port(ffrstmux, AB)) >= offset + GetSize(argD) filter port(ffrstmux, AB).extract(offset, GetSize(argD)) == argD @@ -532,12 +532,12 @@ match ff index port(ff, \D)[offset] === argD[0] // Check that offset is consistent - filter (!ffcemux && !ffrstmux) || ffoffset == offset + filter (!ffholdmux && !ffrstmux) || ffoffset == offset // Check that the rest of argD is present filter GetSize(port(ff, \D)) >= offset + GetSize(argD) filter port(ff, \D).extract(offset, GetSize(argD)) == argD // Check that FF.Q is connected to CE-mux - filter !ffcemux || port(ff, \Q).extract(offset, GetSize(argQ)) == argQ + filter !ffholdmux || port(ff, \Q).extract(offset, GetSize(argQ)) == argQ set ffoffset offset endmatch @@ -552,7 +552,7 @@ code argQ } SigSpec D = port(ff, \D); SigSpec Q = port(ff, \Q); - if (!ffcemux) { + if (!ffholdmux) { argQ = argD; argQ.replace(D, Q); } @@ -569,6 +569,6 @@ code argQ dffclock_pol = param(ff, \CLK_POLARITY).as_bool(); } // No enable/reset mux possible without flop - else if (dffcemux || dffrstmux) + else if (dffholdmux || dffrstmux) reject; endcode -- cgit v1.2.3 From ea5e5a212eeabc5e93d8636c92e92cb5881369ee Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 19 Sep 2019 14:34:06 -0700 Subject: Cleanup xilinx_dsp too --- passes/pmgen/xilinx_dsp.pmg | 65 +++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 37 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 31ab75f09..c6120695a 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -393,6 +393,11 @@ match ff slice offset GetSize(port(ff, \D)) index port(ff, \Q)[offset] === argQ[0] + + // Check that the rest of argQ is present + filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ) + filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ + set ffoffset offset endmatch @@ -402,12 +407,6 @@ code argQ argD reject; SigSpec Q = port(ff, \Q); - if (ffoffset + GetSize(argQ) > GetSize(Q)) - reject; - for (int i = 1; i < GetSize(argQ); i++) - if (Q[ffoffset+i] != argQ[i]) - reject; - dff = ff; dffclock = port(ff, \CLK); dffD = argQ; @@ -481,6 +480,9 @@ arg argD argQ clock code dff = nullptr; + for (auto c : argD.chunks()) + if (c.wire->get_bool_attribute(\keep)) + reject; endcode match ffcemux @@ -495,8 +497,13 @@ match ffcemux slice offset GetSize(port(ffcemux, \Y)) define BA (AB == \A ? \B : \A) index port(ffcemux, BA)[offset] === argD[0] + + // Check that the rest of argD is present + filter GetSize(port(ffcemux, BA)) >= offset + GetSize(argD) + filter port(ffcemux, BA).extract(offset, GetSize(argD)) == argD + set ffoffset offset - define pol (BA == \B) + define pol (AB == \A) set ffcepol pol semioptional @@ -506,12 +513,6 @@ code argD argQ dffcemux = ffcemux; if (ffcemux) { SigSpec BA = port(ffcemux, ffcepol ? \B : \A); - if (ffoffset + GetSize(argD) > GetSize(BA)) - reject; - for (int i = 1; i < GetSize(argD); i++) - if (BA[ffoffset+i] != argD[i]) - reject; - SigSpec Y = port(ffcemux, \Y); argQ = argD; argD.replace(BA, Y); @@ -535,7 +536,12 @@ match ffrstmux define AB (BA == \B ? \A : \B) index port(ffrstmux, AB)[offset] === argD[0] + // Check that offset is consistent filter !ffcemux || ffoffset == offset + // Check that the rest of argD is present + filter GetSize(port(ffrstmux, AB)) >= offset + GetSize(argD) + filter port(ffrstmux, AB).extract(offset, GetSize(argD)) == argD + set ffoffset offset define pol (AB == \A) set ffrstpol pol @@ -547,13 +553,6 @@ code argD argQ dffrstmux = ffrstmux; if (ffrstmux) { SigSpec AB = port(ffrstmux, ffrstpol ? \A : \B); - if (ffoffset + GetSize(argD) > GetSize(AB)) - reject; - - for (int i = 1; i < GetSize(argD); i++) - if (AB[ffoffset+i] != argD[i]) - reject; - SigSpec Y = port(ffrstmux, \Y); argD.replace(AB, Y); @@ -570,10 +569,15 @@ match ff slice offset GetSize(port(ff, \D)) index port(ff, \D)[offset] === argD[0] + // Check that offset is consistent filter (!ffcemux && !ffrstmux) || ffoffset == offset - set ffoffset offset + // Check that the rest of argD is present + filter GetSize(port(ff, \D)) >= offset + GetSize(argD) + filter port(ff, \D).extract(offset, GetSize(argD)) == argD + // Check that FF.Q is connected to CE-mux + filter !ffcemux || port(ff, \Q).extract(offset, GetSize(argQ)) == argQ - semioptional + set ffoffset offset endmatch code argQ @@ -582,26 +586,13 @@ code argQ reject; SigSpec D = port(ff, \D); - if (ffoffset + GetSize(argD) > GetSize(D)) - reject; - for (int i = 1; i < GetSize(argD); i++) - if (D[ffoffset+i] != argD[i]) - reject; - SigSpec Q = port(ff, \Q); - if (ffcemux) { - for (int i = 0; i < GetSize(argQ); i++) - if (Q[ffoffset+i] != argQ[i]) - reject; - } - else { + if (!ffcemux) { argQ = argD; argQ.replace(D, Q); } for (auto c : argQ.chunks()) { - if (c.wire->get_bool_attribute(\keep)) - reject; Const init = c.wire->attributes.at(\init, State::Sx); if (!init.is_fully_undef() && !init.is_fully_zero()) reject; @@ -609,7 +600,7 @@ code argQ dff = ff; dffQ = argQ; - dffclock = port(dff, \CLK); + dffclock = port(ff, \CLK); } // No enable/reset mux possible without flop else if (dffcemux || dffrstmux) -- cgit v1.2.3 From 307b2dc8e58447acae3b56b869fc3783b58ed734 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 19 Sep 2019 14:46:53 -0700 Subject: Revert index to select --- passes/pmgen/ice40_dsp.pmg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index aa081241d..73e92031e 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -215,7 +215,7 @@ endcode match mux select mux->type == $mux choice AB {\A, \B} - index nusers(port(mux, AB)) === 2 + select nusers(port(mux, AB)) == 2 index port(mux, AB) === sigO set muxAB AB optional -- cgit v1.2.3 From 517ca49963a8f186b9f7b54b63e576b4ffb5b847 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 19 Sep 2019 14:49:47 -0700 Subject: Remove TODO as check should not be necessary --- passes/pmgen/ice40_dsp.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index b119b6b7c..01a0869cc 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -180,7 +180,6 @@ void create_ice40_dsp(ice40_dsp_pm &pm) if (O_width == 33) { log_assert(st.add); // If we have a signed multiply-add, then perform sign extension - // TODO: Need to check CD[31:16] is sign extension of CD[15:0]? if (st.add->getParam("\\A_SIGNED").as_bool() && st.add->getParam("\\B_SIGNED").as_bool()) pm.module->connect(O[32], O[31]); else -- cgit v1.2.3 From 64a72ed51e9d21cf5f30e3ff87856c808cf53a29 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 19 Sep 2019 14:50:11 -0700 Subject: Do not perform width-checks for DSP48E1 which is much more complicated --- passes/pmgen/xilinx_dsp.pmg | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index c6120695a..f0537670f 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -278,17 +278,6 @@ endmatch code sigC sigP if (postAdd) { sigC = port(postAdd, postAddAB == \A ? \B : \A); - - // TODO for DSP48E1, which will have sign extended inputs/outputs - //int natural_mul_width = GetSize(port(dsp, \A)) + GetSize(port(dsp, \B)); - //int actual_mul_width = GetSize(sigP); - //int actual_acc_width = GetSize(sigC); - - //if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width)) - // reject; - //if ((actual_acc_width != actual_mul_width) && (param(dsp, \A_SIGNED).as_bool() != param(postAdd, \A_SIGNED).as_bool())) - // reject; - sigP = port(postAdd, \Y); } endcode -- cgit v1.2.3 From 37b0fc17e32d84698b6fa4ccbcff40155351e290 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 19 Sep 2019 15:40:17 -0700 Subject: Re-enable sign extension for C input --- passes/pmgen/xilinx_dsp.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 5af48e4d2..ce75be0e9 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -322,10 +322,10 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) opmode[5] = State::S1; if (opmode[4] != State::S0) { - //if (st.postAddMuxAB == "\\A") - // st.sigC.extend_u0(48, st.postAdd->getParam("\\B_SIGNED").as_bool()); - //else - // st.sigC.extend_u0(48, st.postAdd->getParam("\\A_SIGNED").as_bool()); + if (st.postAddMuxAB == "\\A") + st.sigC.extend_u0(48, st.postAdd->getParam("\\B_SIGNED").as_bool()); + else + st.sigC.extend_u0(48, st.postAdd->getParam("\\A_SIGNED").as_bool()); cell->setPort("\\C", st.sigC); } -- cgit v1.2.3 From a8bc46080548550e020155d1436470e0d3651eca Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 19 Sep 2019 16:13:22 -0700 Subject: Use ID() macro --- passes/pmgen/ice40_dsp.cc | 148 ++++++++++++------------ passes/pmgen/xilinx_dsp.cc | 272 ++++++++++++++++++++++----------------------- 2 files changed, 210 insertions(+), 210 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 01a0869cc..ed3577400 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -65,21 +65,21 @@ void create_ice40_dsp(ice40_dsp_pm &pm) } Cell *cell = st.mul; - if (cell->type == "$mul") { + if (cell->type == ID($mul)) { log(" replacing %s with SB_MAC16 cell.\n", log_id(st.mul->type)); - cell = pm.module->addCell(NEW_ID, "\\SB_MAC16"); + cell = pm.module->addCell(NEW_ID, ID(SB_MAC16)); pm.module->swap_names(cell, st.mul); } - else log_assert(cell->type == "\\SB_MAC16"); + else log_assert(cell->type == ID(SB_MAC16)); // SB_MAC16 Input Interface SigSpec A = st.sigA; - A.extend_u0(16, st.mul->getParam("\\A_SIGNED").as_bool()); + A.extend_u0(16, st.mul->getParam(ID(A_SIGNED)).as_bool()); log_assert(GetSize(A) == 16); SigSpec B = st.sigB; - B.extend_u0(16, st.mul->getParam("\\B_SIGNED").as_bool()); + B.extend_u0(16, st.mul->getParam(ID(B_SIGNED)).as_bool()); log_assert(GetSize(B) == 16); SigSpec CD = st.sigCD; @@ -88,51 +88,51 @@ void create_ice40_dsp(ice40_dsp_pm &pm) else log_assert(GetSize(CD) == 32); - cell->setPort("\\A", A); - cell->setPort("\\B", B); - cell->setPort("\\C", CD.extract(16, 16)); - cell->setPort("\\D", CD.extract(0, 16)); + cell->setPort(ID::A, A); + cell->setPort(ID::B, B); + cell->setPort(ID(C), CD.extract(16, 16)); + cell->setPort(ID(D), CD.extract(0, 16)); - cell->setParam("\\A_REG", st.ffA ? State::S1 : State::S0); - cell->setParam("\\B_REG", st.ffB ? State::S1 : State::S0); - cell->setParam("\\C_REG", st.ffCD ? State::S1 : State::S0); - cell->setParam("\\D_REG", st.ffCD ? State::S1 : State::S0); + cell->setParam(ID(A_REG), st.ffA ? State::S1 : State::S0); + cell->setParam(ID(B_REG), st.ffB ? State::S1 : State::S0); + cell->setParam(ID(C_REG), st.ffCD ? State::S1 : State::S0); + cell->setParam(ID(D_REG), st.ffCD ? State::S1 : State::S0); SigSpec AHOLD, BHOLD, CDHOLD; if (st.ffAholdmux) - AHOLD = st.ffAholdpol ? st.ffAholdmux->getPort("\\S") : pm.module->Not(NEW_ID, st.ffAholdmux->getPort("\\S")); + AHOLD = st.ffAholdpol ? st.ffAholdmux->getPort(ID(S)) : pm.module->Not(NEW_ID, st.ffAholdmux->getPort(ID(S))); else AHOLD = State::S0; if (st.ffBholdmux) - BHOLD = st.ffBholdpol ? st.ffBholdmux->getPort("\\S") : pm.module->Not(NEW_ID, st.ffBholdmux->getPort("\\S")); + BHOLD = st.ffBholdpol ? st.ffBholdmux->getPort(ID(S)) : pm.module->Not(NEW_ID, st.ffBholdmux->getPort(ID(S))); else BHOLD = State::S0; if (st.ffCDholdmux) - CDHOLD = st.ffCDholdpol ? st.ffCDholdmux->getPort("\\S") : pm.module->Not(NEW_ID, st.ffCDholdmux->getPort("\\S")); + CDHOLD = st.ffCDholdpol ? st.ffCDholdmux->getPort(ID(S)) : pm.module->Not(NEW_ID, st.ffCDholdmux->getPort(ID(S))); else CDHOLD = State::S0; - cell->setPort("\\AHOLD", AHOLD); - cell->setPort("\\BHOLD", BHOLD); - cell->setPort("\\CHOLD", CDHOLD); - cell->setPort("\\DHOLD", CDHOLD); + cell->setPort(ID(AHOLD), AHOLD); + cell->setPort(ID(BHOLD), BHOLD); + cell->setPort(ID(CHOLD), CDHOLD); + cell->setPort(ID(DHOLD), CDHOLD); SigSpec IRSTTOP, IRSTBOT; if (st.ffArstmux) - IRSTTOP = st.ffArstpol ? st.ffArstmux->getPort("\\S") : pm.module->Not(NEW_ID, st.ffArstmux->getPort("\\S")); + IRSTTOP = st.ffArstpol ? st.ffArstmux->getPort(ID(S)) : pm.module->Not(NEW_ID, st.ffArstmux->getPort(ID(S))); else IRSTTOP = State::S0; if (st.ffBrstmux) - IRSTBOT = st.ffBrstpol ? st.ffBrstmux->getPort("\\S") : pm.module->Not(NEW_ID, st.ffBrstmux->getPort("\\S")); + IRSTBOT = st.ffBrstpol ? st.ffBrstmux->getPort(ID(S)) : pm.module->Not(NEW_ID, st.ffBrstmux->getPort(ID(S))); else IRSTBOT = State::S0; - cell->setPort("\\IRSTTOP", IRSTTOP); - cell->setPort("\\IRSTBOT", IRSTBOT); + cell->setPort(ID(IRSTTOP), IRSTTOP); + cell->setPort(ID(IRSTBOT), IRSTBOT); if (st.clock != SigBit()) { - cell->setPort("\\CLK", st.clock); - cell->setPort("\\CE", State::S1); - cell->setParam("\\NEG_TRIGGER", st.clock_pol ? State::S0 : State::S1); + cell->setPort(ID(CLK), st.clock); + cell->setPort(ID(CE), State::S1); + cell->setParam(ID(NEG_TRIGGER), st.clock_pol ? State::S0 : State::S1); log(" clock: %s (%s)", log_signal(st.clock), st.clock_pol ? "posedge" : "negedge"); @@ -158,20 +158,20 @@ void create_ice40_dsp(ice40_dsp_pm &pm) } else { - cell->setPort("\\CLK", State::S0); - cell->setPort("\\CE", State::S0); - cell->setParam("\\NEG_TRIGGER", State::S0); + cell->setPort(ID(CLK), State::S0); + cell->setPort(ID(CE), State::S0); + cell->setParam(ID(NEG_TRIGGER), State::S0); } // SB_MAC16 Cascade Interface - cell->setPort("\\SIGNEXTIN", State::Sx); - cell->setPort("\\SIGNEXTOUT", pm.module->addWire(NEW_ID)); + cell->setPort(ID(SIGNEXTIN), State::Sx); + cell->setPort(ID(SIGNEXTOUT), pm.module->addWire(NEW_ID)); - cell->setPort("\\CI", State::Sx); + cell->setPort(ID(CI), State::Sx); - cell->setPort("\\ACCUMCI", State::Sx); - cell->setPort("\\ACCUMCO", pm.module->addWire(NEW_ID)); + cell->setPort(ID(ACCUMCI), State::Sx); + cell->setPort(ID(ACCUMCO), pm.module->addWire(NEW_ID)); // SB_MAC16 Output Interface @@ -180,91 +180,91 @@ void create_ice40_dsp(ice40_dsp_pm &pm) if (O_width == 33) { log_assert(st.add); // If we have a signed multiply-add, then perform sign extension - if (st.add->getParam("\\A_SIGNED").as_bool() && st.add->getParam("\\B_SIGNED").as_bool()) + if (st.add->getParam(ID(A_SIGNED)).as_bool() && st.add->getParam(ID(B_SIGNED)).as_bool()) pm.module->connect(O[32], O[31]); else - cell->setPort("\\CO", O[32]); + cell->setPort(ID(CO), O[32]); O.remove(O_width-1); } else - cell->setPort("\\CO", pm.module->addWire(NEW_ID)); + cell->setPort(ID(CO), pm.module->addWire(NEW_ID)); log_assert(GetSize(O) <= 32); if (GetSize(O) < 32) O.append(pm.module->addWire(NEW_ID, 32-GetSize(O))); - cell->setPort("\\O", O); + cell->setPort(ID(O), O); bool accum = false; if (st.add) { - accum = (st.ffO && st.add->getPort(st.addAB == "\\A" ? "\\B" : "\\A") == st.sigO); + accum = (st.ffO && st.add->getPort(st.addAB == ID::A ? ID::B : ID::A) == st.sigO); if (accum) log(" accumulator %s (%s)\n", log_id(st.add), log_id(st.add->type)); else log(" adder %s (%s)\n", log_id(st.add), log_id(st.add->type)); - cell->setPort("\\ADDSUBTOP", st.add->type == "$add" ? State::S0 : State::S1); - cell->setPort("\\ADDSUBBOT", st.add->type == "$add" ? State::S0 : State::S1); + cell->setPort(ID(ADDSUBTOP), st.add->type == ID($add) ? State::S0 : State::S1); + cell->setPort(ID(ADDSUBBOT), st.add->type == ID($add) ? State::S0 : State::S1); } else { - cell->setPort("\\ADDSUBTOP", State::S0); - cell->setPort("\\ADDSUBBOT", State::S0); + cell->setPort(ID(ADDSUBTOP), State::S0); + cell->setPort(ID(ADDSUBBOT), State::S0); } SigSpec OHOLD; if (st.ffOholdmux) - OHOLD = st.ffOholdpol ? st.ffOholdmux->getPort("\\S") : pm.module->Not(NEW_ID, st.ffOholdmux->getPort("\\S")); + OHOLD = st.ffOholdpol ? st.ffOholdmux->getPort(ID(S)) : pm.module->Not(NEW_ID, st.ffOholdmux->getPort(ID(S))); else OHOLD = State::S0; - cell->setPort("\\OHOLDTOP", OHOLD); - cell->setPort("\\OHOLDBOT", OHOLD); + cell->setPort(ID(OHOLDTOP), OHOLD); + cell->setPort(ID(OHOLDBOT), OHOLD); SigSpec ORST; if (st.ffOrstmux) - ORST = st.ffOrstpol ? st.ffOrstmux->getPort("\\S") : pm.module->Not(NEW_ID, st.ffOrstmux->getPort("\\S")); + ORST = st.ffOrstpol ? st.ffOrstmux->getPort(ID(S)) : pm.module->Not(NEW_ID, st.ffOrstmux->getPort(ID(S))); else ORST = State::S0; - cell->setPort("\\ORSTTOP", ORST); - cell->setPort("\\ORSTBOT", ORST); + cell->setPort(ID(ORSTTOP), ORST); + cell->setPort(ID(ORSTBOT), ORST); SigSpec acc_reset = State::S0; if (st.mux) { - if (st.muxAB == "\\A") - acc_reset = st.mux->getPort("\\S"); + if (st.muxAB == ID::A) + acc_reset = st.mux->getPort(ID(S)); else - acc_reset = pm.module->Not(NEW_ID, st.mux->getPort("\\S")); + acc_reset = pm.module->Not(NEW_ID, st.mux->getPort(ID(S))); } - cell->setPort("\\OLOADTOP", acc_reset); - cell->setPort("\\OLOADBOT", acc_reset); + cell->setPort(ID(OLOADTOP), acc_reset); + cell->setPort(ID(OLOADBOT), acc_reset); // SB_MAC16 Remaining Parameters - cell->setParam("\\TOP_8x8_MULT_REG", st.ffFJKG ? State::S1 : State::S0); - cell->setParam("\\BOT_8x8_MULT_REG", st.ffFJKG ? State::S1 : State::S0); - cell->setParam("\\PIPELINE_16x16_MULT_REG1", st.ffFJKG ? State::S1 : State::S0); - cell->setParam("\\PIPELINE_16x16_MULT_REG2", st.ffH ? State::S1 : State::S0); + cell->setParam(ID(TOP_8x8_MULT_REG), st.ffFJKG ? State::S1 : State::S0); + cell->setParam(ID(BOT_8x8_MULT_REG), st.ffFJKG ? State::S1 : State::S0); + cell->setParam(ID(PIPELINE_16x16_MULT_REG1), st.ffFJKG ? State::S1 : State::S0); + cell->setParam(ID(PIPELINE_16x16_MULT_REG2), st.ffH ? State::S1 : State::S0); - cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2)); - cell->setParam("\\TOPADDSUB_UPPERINPUT", accum ? State::S0 : State::S1); - cell->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2)); + cell->setParam(ID(TOPADDSUB_LOWERINPUT), Const(2, 2)); + cell->setParam(ID(TOPADDSUB_UPPERINPUT), accum ? State::S0 : State::S1); + cell->setParam(ID(TOPADDSUB_CARRYSELECT), Const(3, 2)); - cell->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2)); - cell->setParam("\\BOTADDSUB_UPPERINPUT", accum ? State::S0 : State::S1); - cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2)); + cell->setParam(ID(BOTADDSUB_LOWERINPUT), Const(2, 2)); + cell->setParam(ID(BOTADDSUB_UPPERINPUT), accum ? State::S0 : State::S1); + cell->setParam(ID(BOTADDSUB_CARRYSELECT), Const(0, 2)); - cell->setParam("\\MODE_8x8", State::S0); - cell->setParam("\\A_SIGNED", st.mul->getParam("\\A_SIGNED").as_bool()); - cell->setParam("\\B_SIGNED", st.mul->getParam("\\B_SIGNED").as_bool()); + cell->setParam(ID(MODE_8x8), State::S0); + cell->setParam(ID(A_SIGNED), st.mul->getParam(ID(A_SIGNED)).as_bool()); + cell->setParam(ID(B_SIGNED), st.mul->getParam(ID(B_SIGNED)).as_bool()); if (st.ffO) { if (st.o_lo) - cell->setParam("\\TOPOUTPUT_SELECT", Const(st.add ? 0 : 3, 2)); + cell->setParam(ID(TOPOUTPUT_SELECT), Const(st.add ? 0 : 3, 2)); else - cell->setParam("\\TOPOUTPUT_SELECT", Const(1, 2)); + cell->setParam(ID(TOPOUTPUT_SELECT), Const(1, 2)); - st.ffO->connections_.at("\\Q").replace(O, pm.module->addWire(NEW_ID, GetSize(O))); - cell->setParam("\\BOTOUTPUT_SELECT", Const(1, 2)); + st.ffO->connections_.at(ID(Q)).replace(O, pm.module->addWire(NEW_ID, GetSize(O))); + cell->setParam(ID(BOTOUTPUT_SELECT), Const(1, 2)); } else { - cell->setParam("\\TOPOUTPUT_SELECT", Const(st.add ? 0 : 3, 2)); - cell->setParam("\\BOTOUTPUT_SELECT", Const(st.add ? 0 : 3, 2)); + cell->setParam(ID(TOPOUTPUT_SELECT), Const(st.add ? 0 : 3, 2)); + cell->setParam(ID(BOTOUTPUT_SELECT), Const(st.add ? 0 : 3, 2)); } if (cell != st.mul) diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index ce75be0e9..3cfaa9371 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -27,36 +27,36 @@ PRIVATE_NAMESPACE_BEGIN #include "passes/pmgen/xilinx_dsp_pm.h" static Cell* addDsp(Module *module) { - Cell *cell = module->addCell(NEW_ID, "\\DSP48E1"); - cell->setParam("\\ACASCREG", 0); - cell->setParam("\\ADREG", 0); - cell->setParam("\\A_INPUT", Const("DIRECT")); - cell->setParam("\\ALUMODEREG", 0); - cell->setParam("\\AREG", 0); - cell->setParam("\\BCASCREG", 0); - cell->setParam("\\B_INPUT", Const("DIRECT")); - cell->setParam("\\BREG", 0); - cell->setParam("\\CARRYINREG", 0); - cell->setParam("\\CARRYINSELREG", 0); - cell->setParam("\\CREG", 0); - cell->setParam("\\DREG", 0); - cell->setParam("\\INMODEREG", 0); - cell->setParam("\\MREG", 0); - cell->setParam("\\OPMODEREG", 0); - cell->setParam("\\PREG", 0); - cell->setParam("\\USE_MULT", Const("NONE")); - cell->setParam("\\USE_SIMD", Const("ONE48")); - cell->setParam("\\USE_DPORT", Const("FALSE")); - - cell->setPort("\\D", Const(0, 24)); - cell->setPort("\\INMODE", Const(0, 5)); - cell->setPort("\\ALUMODE", Const(0, 4)); - cell->setPort("\\OPMODE", Const(0, 7)); - cell->setPort("\\CARRYINSEL", Const(0, 3)); - cell->setPort("\\ACIN", Const(0, 30)); - cell->setPort("\\BCIN", Const(0, 18)); - cell->setPort("\\PCIN", Const(0, 48)); - cell->setPort("\\CARRYIN", Const(0, 1)); + Cell *cell = module->addCell(NEW_ID, ID(DSP48E1)); + cell->setParam(ID(ACASCREG), 0); + cell->setParam(ID(ADREG), 0); + cell->setParam(ID(A_INPUT), Const("DIRECT")); + cell->setParam(ID(ALUMODEREG), 0); + cell->setParam(ID(AREG), 0); + cell->setParam(ID(BCASCREG), 0); + cell->setParam(ID(B_INPUT), Const("DIRECT")); + cell->setParam(ID(BREG), 0); + cell->setParam(ID(CARRYINREG), 0); + cell->setParam(ID(CARRYINSELREG), 0); + cell->setParam(ID(CREG), 0); + cell->setParam(ID(DREG), 0); + cell->setParam(ID(INMODEREG), 0); + cell->setParam(ID(MREG), 0); + cell->setParam(ID(OPMODEREG), 0); + cell->setParam(ID(PREG), 0); + cell->setParam(ID(USE_MULT), Const("NONE")); + cell->setParam(ID(USE_SIMD), Const("ONE48")); + cell->setParam(ID(USE_DPORT), Const("FALSE")); + + cell->setPort(ID(D), Const(0, 24)); + cell->setPort(ID(INMODE), Const(0, 5)); + cell->setPort(ID(ALUMODE), Const(0, 4)); + cell->setPort(ID(OPMODE), Const(0, 7)); + cell->setPort(ID(CARRYINSEL), Const(0, 3)); + cell->setPort(ID(ACIN), Const(0, 30)); + cell->setPort(ID(BCIN), Const(0, 18)); + cell->setPort(ID(PCIN), Const(0, 48)); + cell->setPort(ID(CARRYIN), Const(0, 1)); return cell; } @@ -66,25 +66,25 @@ void pack_xilinx_simd(Module *module, const std::vector &selected_cells) std::deque simd24_add, simd24_sub; for (auto cell : selected_cells) { - if (!cell->type.in("$add", "$sub")) + if (!cell->type.in(ID($add), ID($sub))) continue; - SigSpec Y = cell->getPort("\\Y"); + SigSpec Y = cell->getPort(ID(Y)); if (!Y.is_chunk()) continue; - if (!Y.as_chunk().wire->get_strpool_attribute("\\use_dsp").count("simd")) + if (!Y.as_chunk().wire->get_strpool_attribute(ID(use_dsp)).count("simd")) continue; if (GetSize(Y) > 25) continue; - SigSpec A = cell->getPort("\\A"); - SigSpec B = cell->getPort("\\B"); + SigSpec A = cell->getPort(ID(A)); + SigSpec B = cell->getPort(ID(B)); if (GetSize(Y) <= 13) { if (GetSize(A) > 12) continue; if (GetSize(B) > 12) continue; - if (cell->type == "$add") + if (cell->type == ID($add)) simd12_add.push_back(cell); - else if (cell->type == "$sub") + else if (cell->type == ID($sub)) simd12_sub.push_back(cell); } else if (GetSize(Y) <= 25) { @@ -92,9 +92,9 @@ void pack_xilinx_simd(Module *module, const std::vector &selected_cells) continue; if (GetSize(B) > 24) continue; - if (cell->type == "$add") + if (cell->type == ID($add)) simd24_add.push_back(cell); - else if (cell->type == "$sub") + else if (cell->type == ID($sub)) simd24_sub.push_back(cell); } else @@ -102,11 +102,11 @@ void pack_xilinx_simd(Module *module, const std::vector &selected_cells) } auto f12 = [module](SigSpec &AB, SigSpec &C, SigSpec &P, SigSpec &CARRYOUT, Cell *lane) { - SigSpec A = lane->getPort("\\A"); - SigSpec B = lane->getPort("\\B"); - SigSpec Y = lane->getPort("\\Y"); - A.extend_u0(12, lane->getParam("\\A_SIGNED").as_bool()); - B.extend_u0(12, lane->getParam("\\B_SIGNED").as_bool()); + SigSpec A = lane->getPort(ID(A)); + SigSpec B = lane->getPort(ID(B)); + SigSpec Y = lane->getPort(ID(Y)); + A.extend_u0(12, lane->getParam(ID(A_SIGNED)).as_bool()); + B.extend_u0(12, lane->getParam(ID(B_SIGNED)).as_bool()); AB.append(A); C.append(B); if (GetSize(Y) < 13) @@ -139,11 +139,11 @@ void pack_xilinx_simd(Module *module, const std::vector &selected_cells) log("Analysing %s.%s for Xilinx DSP SIMD12 packing.\n", log_id(module), log_id(lane1)); Cell *cell = addDsp(module); - cell->setParam("\\USE_SIMD", Const("FOUR12")); + cell->setParam(ID(USE_SIMD), Const("FOUR12")); // X = A:B // Y = 0 // Z = C - cell->setPort("\\OPMODE", Const::from_string("0110011")); + cell->setPort(ID(OPMODE), Const::from_string("0110011")); log_assert(lane1); log_assert(lane2); @@ -170,13 +170,13 @@ void pack_xilinx_simd(Module *module, const std::vector &selected_cells) log_assert(GetSize(C) == 48); log_assert(GetSize(P) == 48); log_assert(GetSize(CARRYOUT) == 4); - cell->setPort("\\A", AB.extract(18, 30)); - cell->setPort("\\B", AB.extract(0, 18)); - cell->setPort("\\C", C); - cell->setPort("\\P", P); - cell->setPort("\\CARRYOUT", CARRYOUT); - if (lane1->type == "$sub") - cell->setPort("\\ALUMODE", Const::from_string("0011")); + cell->setPort(ID(A), AB.extract(18, 30)); + cell->setPort(ID(B), AB.extract(0, 18)); + cell->setPort(ID(C), C); + cell->setPort(ID(P), P); + cell->setPort(ID(CARRYOUT), CARRYOUT); + if (lane1->type == ID($sub)) + cell->setPort(ID(ALUMODE), Const::from_string("0011")); module->remove(lane1); module->remove(lane2); @@ -190,11 +190,11 @@ void pack_xilinx_simd(Module *module, const std::vector &selected_cells) g12(simd12_sub); auto f24 = [module](SigSpec &AB, SigSpec &C, SigSpec &P, SigSpec &CARRYOUT, Cell *lane) { - SigSpec A = lane->getPort("\\A"); - SigSpec B = lane->getPort("\\B"); - SigSpec Y = lane->getPort("\\Y"); - A.extend_u0(24, lane->getParam("\\A_SIGNED").as_bool()); - B.extend_u0(24, lane->getParam("\\B_SIGNED").as_bool()); + SigSpec A = lane->getPort(ID(A)); + SigSpec B = lane->getPort(ID(B)); + SigSpec Y = lane->getPort(ID(Y)); + A.extend_u0(24, lane->getParam(ID(A_SIGNED)).as_bool()); + B.extend_u0(24, lane->getParam(ID(B_SIGNED)).as_bool()); C.append(A); AB.append(B); if (GetSize(Y) < 25) @@ -220,11 +220,11 @@ void pack_xilinx_simd(Module *module, const std::vector &selected_cells) log("Analysing %s.%s for Xilinx DSP SIMD24 packing.\n", log_id(module), log_id(lane1)); Cell *cell = addDsp(module); - cell->setParam("\\USE_SIMD", Const("TWO24")); + cell->setParam(ID(USE_SIMD), Const("TWO24")); // X = A:B // Y = 0 // Z = C - cell->setPort("\\OPMODE", Const::from_string("0110011")); + cell->setPort(ID(OPMODE), Const::from_string("0110011")); log_assert(lane1); log_assert(lane2); @@ -234,13 +234,13 @@ void pack_xilinx_simd(Module *module, const std::vector &selected_cells) log_assert(GetSize(C) == 48); log_assert(GetSize(P) == 48); log_assert(GetSize(CARRYOUT) == 4); - cell->setPort("\\A", AB.extract(18, 30)); - cell->setPort("\\B", AB.extract(0, 18)); - cell->setPort("\\C", C); - cell->setPort("\\P", P); - cell->setPort("\\CARRYOUT", CARRYOUT); - if (lane1->type == "$sub") - cell->setPort("\\ALUMODE", Const::from_string("0011")); + cell->setPort(ID(A), AB.extract(18, 30)); + cell->setPort(ID(B), AB.extract(0, 18)); + cell->setPort(ID(C), C); + cell->setPort(ID(P), P); + cell->setPort(ID(CARRYOUT), CARRYOUT); + if (lane1->type == ID($sub)) + cell->setPort(ID(ALUMODE), Const::from_string("0011")); module->remove(lane1); module->remove(lane2); @@ -281,37 +281,37 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) if (st.preAdd) { log(" preadder %s (%s)\n", log_id(st.preAdd), log_id(st.preAdd->type)); - bool A_SIGNED = st.preAdd->getParam("\\A_SIGNED").as_bool(); - bool D_SIGNED = st.preAdd->getParam("\\B_SIGNED").as_bool(); - if (st.sigA == st.preAdd->getPort("\\B")) + bool A_SIGNED = st.preAdd->getParam(ID(A_SIGNED)).as_bool(); + bool D_SIGNED = st.preAdd->getParam(ID(B_SIGNED)).as_bool(); + if (st.sigA == st.preAdd->getPort(ID(B))) std::swap(A_SIGNED, D_SIGNED); st.sigA.extend_u0(30, A_SIGNED); st.sigD.extend_u0(25, D_SIGNED); - cell->setPort("\\A", st.sigA); - cell->setPort("\\D", st.sigD); - cell->connections_.at("\\INMODE") = Const::from_string("00100"); + cell->setPort(ID(A), st.sigA); + cell->setPort(ID(D), st.sigD); + cell->connections_.at(ID(INMODE)) = Const::from_string("00100"); if (st.ffAD) { if (st.ffADcemux) { - SigSpec S = st.ffADcemux->getPort("\\S"); - cell->setPort("\\CEAD", st.ffADcepol ? S : pm.module->Not(NEW_ID, S)); + SigSpec S = st.ffADcemux->getPort(ID(S)); + cell->setPort(ID(CEAD), st.ffADcepol ? S : pm.module->Not(NEW_ID, S)); } else - cell->setPort("\\CEAD", State::S1); - cell->setParam("\\ADREG", 1); + cell->setPort(ID(CEAD), State::S1); + cell->setParam(ID(ADREG), 1); } - cell->setParam("\\USE_DPORT", Const("TRUE")); + cell->setParam(ID(USE_DPORT), Const("TRUE")); pm.autoremove(st.preAdd); } if (st.postAdd) { log(" postadder %s (%s)\n", log_id(st.postAdd), log_id(st.postAdd->type)); - SigSpec &opmode = cell->connections_.at("\\OPMODE"); + SigSpec &opmode = cell->connections_.at(ID(OPMODE)); if (st.postAddMux) { log_assert(st.ffP); - opmode[4] = st.postAddMux->getPort("\\S"); + opmode[4] = st.postAddMux->getPort(ID(S)); pm.autoremove(st.postAddMux); } else if (st.ffP && st.sigC == st.sigP) @@ -322,23 +322,23 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) opmode[5] = State::S1; if (opmode[4] != State::S0) { - if (st.postAddMuxAB == "\\A") - st.sigC.extend_u0(48, st.postAdd->getParam("\\B_SIGNED").as_bool()); + if (st.postAddMuxAB == ID(A)) + st.sigC.extend_u0(48, st.postAdd->getParam(ID(B_SIGNED)).as_bool()); else - st.sigC.extend_u0(48, st.postAdd->getParam("\\A_SIGNED").as_bool()); - cell->setPort("\\C", st.sigC); + st.sigC.extend_u0(48, st.postAdd->getParam(ID(A_SIGNED)).as_bool()); + cell->setPort(ID(C), st.sigC); } pm.autoremove(st.postAdd); } if (st.overflow) { log(" overflow %s (%s)\n", log_id(st.overflow), log_id(st.overflow->type)); - cell->setParam("\\USE_PATTERN_DETECT", Const("PATDET")); - cell->setParam("\\SEL_PATTERN", Const("PATTERN")); - cell->setParam("\\SEL_MASK", Const("MASK")); + cell->setParam(ID(USE_PATTERN_DETECT), Const("PATDET")); + cell->setParam(ID(SEL_PATTERN), Const("PATTERN")); + cell->setParam(ID(SEL_MASK), Const("MASK")); - if (st.overflow->type == "$ge") { - Const B = st.overflow->getPort("\\B").as_const(); + if (st.overflow->type == ID($ge)) { + Const B = st.overflow->getPort(ID(B)).as_const(); log_assert(std::count(B.bits.begin(), B.bits.end(), State::S1) == 1); // Since B is an exact power of 2, subtract 1 // by inverting all bits up until hitting @@ -351,9 +351,9 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) } B.extu(48); - cell->setParam("\\MASK", B); - cell->setParam("\\PATTERN", Const(0, 48)); - cell->setPort("\\OVERFLOW", st.overflow->getPort("\\Y")); + cell->setParam(ID(MASK), B); + cell->setParam(ID(PATTERN), Const(0, 48)); + cell->setPort(ID(OVERFLOW), st.overflow->getPort(ID(Y))); } else log_abort(); @@ -362,29 +362,29 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) if (st.clock != SigBit()) { - cell->setPort("\\CLK", st.clock); + cell->setPort(ID(CLK), st.clock); auto f = [&pm,cell](SigSpec &A, Cell* ff, Cell* cemux, bool cepol, IdString ceport, Cell* rstmux, bool rstpol, IdString rstport) { - SigSpec D = ff->getPort("\\D"); - SigSpec Q = pm.sigmap(ff->getPort("\\Q")); + SigSpec D = ff->getPort(ID(D)); + SigSpec Q = pm.sigmap(ff->getPort(ID(Q))); if (!A.empty()) A.replace(Q, D); if (rstmux) { - SigSpec Y = rstmux->getPort("\\Y"); - SigSpec AB = rstmux->getPort(rstpol ? "\\A" : "\\B"); + SigSpec Y = rstmux->getPort(ID(Y)); + SigSpec AB = rstmux->getPort(rstpol ? ID(A) : ID(B)); if (!A.empty()) A.replace(Y, AB); if (rstport != IdString()) { - SigSpec S = rstmux->getPort("\\S"); + SigSpec S = rstmux->getPort(ID(S)); cell->setPort(rstport, rstpol ? S : pm.module->Not(NEW_ID, S)); } } else if (rstport != IdString()) cell->setPort(rstport, State::S0); if (cemux) { - SigSpec Y = cemux->getPort("\\Y"); - SigSpec BA = cemux->getPort(cepol ? "\\B" : "\\A"); - SigSpec S = cemux->getPort("\\S"); + SigSpec Y = cemux->getPort(ID(Y)); + SigSpec BA = cemux->getPort(cepol ? ID(B) : ID(A)); + SigSpec S = cemux->getPort(ID(S)); if (!A.empty()) A.replace(Y, BA); cell->setPort(ceport, cepol ? S : pm.module->Not(NEW_ID, S)); @@ -393,7 +393,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) cell->setPort(ceport, State::S1); for (auto c : Q.chunks()) { - auto it = c.wire->attributes.find("\\init"); + auto it = c.wire->attributes.find(ID(init)); if (it == c.wire->attributes.end()) continue; for (int i = c.offset; i < c.offset+c.width; i++) { @@ -404,50 +404,50 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) }; if (st.ffA2) { - SigSpec &A = cell->connections_.at("\\A"); - f(A, st.ffA2, st.ffA2cemux, st.ffA2cepol, "\\CEA2", st.ffA2rstmux, st.ffArstpol, "\\RSTA"); + SigSpec &A = cell->connections_.at(ID(A)); + f(A, st.ffA2, st.ffA2cemux, st.ffA2cepol, ID(CEA2), st.ffA2rstmux, st.ffArstpol, ID(RSTA)); pm.add_siguser(A, cell); if (st.ffA1) { - f(A, st.ffA1, st.ffA1cemux, st.ffA1cepol, "\\CEA1", st.ffA1rstmux, st.ffArstpol, IdString()); - cell->setParam("\\AREG", 2); + f(A, st.ffA1, st.ffA1cemux, st.ffA1cepol, ID(CEA1), st.ffA1rstmux, st.ffArstpol, IdString()); + cell->setParam(ID(AREG), 2); } else - cell->setParam("\\AREG", 1); + cell->setParam(ID(AREG), 1); } if (st.ffB2) { - SigSpec &B = cell->connections_.at("\\B"); - f(B, st.ffB2, st.ffB2cemux, st.ffB2cepol, "\\CEB2", st.ffB2rstmux, st.ffBrstpol, "\\RSTB"); + SigSpec &B = cell->connections_.at(ID(B)); + f(B, st.ffB2, st.ffB2cemux, st.ffB2cepol, ID(CEB2), st.ffB2rstmux, st.ffBrstpol, ID(RSTB)); pm.add_siguser(B, cell); if (st.ffB1) { - f(B, st.ffB1, st.ffB1cemux, st.ffB1cepol, "\\CEB1", st.ffB1rstmux, st.ffBrstpol, IdString()); - cell->setParam("\\BREG", 2); + f(B, st.ffB1, st.ffB1cemux, st.ffB1cepol, ID(CEB1), st.ffB1rstmux, st.ffBrstpol, IdString()); + cell->setParam(ID(BREG), 2); } else - cell->setParam("\\BREG", 1); + cell->setParam(ID(BREG), 1); } if (st.ffC) { - SigSpec &C = cell->connections_.at("\\C"); - f(C, st.ffC, st.ffCcemux, st.ffCcepol, "\\CEC", st.ffCrstmux, st.ffCrstpol, "\\RSTC"); + SigSpec &C = cell->connections_.at(ID(C)); + f(C, st.ffC, st.ffCcemux, st.ffCcepol, ID(CEC), st.ffCrstmux, st.ffCrstpol, ID(RSTC)); pm.add_siguser(C, cell); - cell->setParam("\\CREG", 1); + cell->setParam(ID(CREG), 1); } if (st.ffD) { - SigSpec &D = cell->connections_.at("\\D"); - f(D, st.ffD, st.ffDcemux, st.ffDcepol, "\\CED", st.ffDrstmux, st.ffDrstpol, "\\RSTD"); + SigSpec &D = cell->connections_.at(ID(D)); + f(D, st.ffD, st.ffDcemux, st.ffDcepol, ID(CED), st.ffDrstmux, st.ffDrstpol, ID(RSTD)); pm.add_siguser(D, cell); - cell->setParam("\\DREG", 1); + cell->setParam(ID(DREG), 1); } if (st.ffM) { SigSpec M; // unused - f(M, st.ffM, st.ffMcemux, st.ffMcepol, "\\CEM", st.ffMrstmux, st.ffMrstpol, "\\RSTM"); - st.ffM->connections_.at("\\Q").replace(st.sigM, pm.module->addWire(NEW_ID, GetSize(st.sigM))); - cell->setParam("\\MREG", State::S1); + f(M, st.ffM, st.ffMcemux, st.ffMcepol, ID(CEM), st.ffMrstmux, st.ffMrstpol, ID(RSTM)); + st.ffM->connections_.at(ID(Q)).replace(st.sigM, pm.module->addWire(NEW_ID, GetSize(st.sigM))); + cell->setParam(ID(MREG), State::S1); } if (st.ffP) { SigSpec P; // unused - f(P, st.ffP, st.ffPcemux, st.ffPcepol, "\\CEP", st.ffPrstmux, st.ffPrstpol, "\\RSTP"); - st.ffP->connections_.at("\\Q").replace(st.sigP, pm.module->addWire(NEW_ID, GetSize(st.sigP))); - cell->setParam("\\PREG", State::S1); + f(P, st.ffP, st.ffPcemux, st.ffPcepol, ID(CEP), st.ffPrstmux, st.ffPrstpol, ID(RSTP)); + st.ffP->connections_.at(ID(Q)).replace(st.sigP, pm.module->addWire(NEW_ID, GetSize(st.sigP))); + cell->setParam(ID(PREG), State::S1); } log(" clock: %s (%s)", log_signal(st.clock), "posedge"); @@ -485,7 +485,7 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) SigSpec P = st.sigP; if (GetSize(P) < 48) P.append(pm.module->addWire(NEW_ID, 48-GetSize(P))); - cell->setPort("\\P", P); + cell->setPort(ID(P), P); bit_to_driver.insert(std::make_pair(P[0], cell)); bit_to_driver.insert(std::make_pair(P[17], cell)); @@ -553,14 +553,14 @@ struct XilinxDspPass : public Pass { // NB: Needs to be done after pattern matcher has folded all // $add cells into the DSP for (auto cell : module->cells()) { - if (cell->type != "\\DSP48E1") + if (cell->type != ID(DSP48E1)) continue; - if (cell->parameters.at("\\CREG", State::S1).as_bool()) + if (cell->parameters.at(ID(CREG), State::S1).as_bool()) continue; - SigSpec &opmode = cell->connections_.at("\\OPMODE"); + SigSpec &opmode = cell->connections_.at(ID(OPMODE)); if (opmode.extract(4,3) != Const::from_string("011")) continue; - SigSpec C = unextend(pm.sigmap(cell->getPort("\\C"))); + SigSpec C = unextend(pm.sigmap(cell->getPort(ID(C)))); if (!C[0].wire) continue; auto it = bit_to_driver.find(C[0]); @@ -568,22 +568,22 @@ struct XilinxDspPass : public Pass { continue; auto driver = it->second; - SigSpec P = driver->getPort("\\P"); + SigSpec P = driver->getPort(ID(P)); if (GetSize(P) >= GetSize(C) && P.extract(0, GetSize(C)) == C) { - cell->setPort("\\C", Const(0, 48)); + cell->setPort(ID(C), Const(0, 48)); Wire *cascade = module->addWire(NEW_ID, 48); - driver->setPort("\\PCOUT", cascade); - cell->setPort("\\PCIN", cascade); + driver->setPort(ID(PCOUT), cascade); + cell->setPort(ID(PCIN), cascade); opmode[6] = State::S0; opmode[5] = State::S0; opmode[4] = State::S1; bit_to_driver.erase(it); } else if (GetSize(P) >= GetSize(C)+17 && P.extract(17, GetSize(C)) == C) { - cell->setPort("\\C", Const(0, 48)); + cell->setPort(ID(C), Const(0, 48)); Wire *cascade = module->addWire(NEW_ID, 48); - driver->setPort("\\PCOUT", cascade); - cell->setPort("\\PCIN", cascade); + driver->setPort(ID(PCOUT), cascade); + cell->setPort(ID(PCIN), cascade); opmode[6] = State::S1; opmode[5] = State::S0; opmode[4] = State::S1; -- cgit v1.2.3 From c83a66755553f47f40c591110e6bdcd722360d6c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 19 Sep 2019 18:08:46 -0700 Subject: Fix width of D --- passes/pmgen/xilinx_dsp.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 3cfaa9371..adc09a6e4 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -48,7 +48,7 @@ static Cell* addDsp(Module *module) { cell->setParam(ID(USE_SIMD), Const("ONE48")); cell->setParam(ID(USE_DPORT), Const("FALSE")); - cell->setPort(ID(D), Const(0, 24)); + cell->setPort(ID(D), Const(0, 25)); cell->setPort(ID(INMODE), Const(0, 5)); cell->setPort(ID(ALUMODE), Const(0, 4)); cell->setPort(ID(OPMODE), Const(0, 7)); -- cgit v1.2.3 From 8a94ce7aa524eea0429446e0a5e8c64bee45ac55 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 19 Sep 2019 20:04:44 -0700 Subject: Add an index --- passes/pmgen/ice40_dsp.pmg | 1 + passes/pmgen/xilinx_dsp.pmg | 2 ++ 2 files changed, 3 insertions(+) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 73e92031e..35db22807 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -189,6 +189,7 @@ match add index port(add, AB)[0] === sigH[0] filter GetSize(port(add, AB)) <= GetSize(sigH) filter port(add, AB) == sigH.extract(0, GetSize(port(add, AB))) + filter nusers(sigH.extract_end(GetSize(port(add, AB)))) <= 1 set addAB AB optional endmatch diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index f0537670f..20565f47d 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -268,6 +268,8 @@ match postAdd select nusers(port(postAdd, AB)) <= 3 filter ffMcemux || nusers(port(postAdd, AB)) == 2 filter !ffMcemux || nusers(port(postAdd, AB)) == 3 + + index port(postAdd, AB)[0] === sigP[0] filter GetSize(unextend(port(postAdd, AB))) <= GetSize(sigP) filter unextend(port(postAdd, AB)) == sigP.extract(0, GetSize(unextend(port(postAdd, AB)))) filter nusers(sigP.extract_end(GetSize(unextend(port(postAdd, AB))))) <= 1 -- cgit v1.2.3 From 34f9a8ceb285b6b59f24f994d3a877d5f4f09572 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 19 Sep 2019 21:57:11 -0700 Subject: Update doc for ice40_dsp --- passes/pmgen/ice40_dsp.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index ed3577400..2d264a6d1 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -283,9 +283,18 @@ struct Ice40DspPass : public Pass { log("\n"); log(" ice40_dsp [options] [selection]\n"); log("\n"); - log("Map multipliers and multiply-accumulate blocks to iCE40 DSP resources.\n"); + log("Map multipliers ($mul/SB_MAC16) and multiply-accumulate ($mul/SB_MAC16 + $add)\n"); + log("cells into iCE40 DSP resources.\n"); log("Currently, only the 16x16 multiply mode is supported and not the 2 x 8x8 mode.\n"); log("\n"); + log("Pack input registers (A, B, {C,D}; with optional hold/reset), pipeline registers\n"); + log("({F,J,K,G}, H; with shared reset), output registers (O; with optional hold/reset),\n"); + log("and post-adder into the SB_MAC16 resource.\n"); + log("\n"); + log("Multiply-accumulate operations using the post-adder with feedback on the {C,D}\n"); + log("input will be folded into the DSP. In this scenario only, resetting the\n"); + log("the accumulator to an arbitrary value can be inferred to use the {C,D} input.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { -- cgit v1.2.3 From 1b88211ec61d70ee34f9dc21647ebd941d91fcb4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 19 Sep 2019 21:58:34 -0700 Subject: Clarify --- passes/pmgen/xilinx_dsp.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index adc09a6e4..abd145723 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -507,7 +507,8 @@ struct XilinxDspPass : public Pass { log("\n"); log("Multiply-accumulate operations using the post-adder with feedback on the 'C'\n"); log("input will be folded into the DSP. In this scenario only, the 'C' input can be\n"); - log("used to override the existing accumulation result with a new value.\n"); + log("used to override the current accumulation result with a new value, which will\n"); + log("be added to the multiplier result to form the next accumulation result.\n"); log("\n"); log("Use of the dedicated 'PCOUT' -> 'PCIN' cascade path is detected for 'P' -> 'C'\n"); log("connections (optionally, where 'P' is right-shifted by 18-bits and used as an\n"); -- cgit v1.2.3 From a59f80834f7f8ecf02ed0c608dce1a237a874d34 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 19 Sep 2019 22:39:47 -0700 Subject: SB_MAC16 ffCD to not pack same as ffO --- passes/pmgen/ice40_dsp.pmg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 35db22807..09fd8406d 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -188,7 +188,7 @@ match add select nusers(port(add, AB)) == 2 index port(add, AB)[0] === sigH[0] filter GetSize(port(add, AB)) <= GetSize(sigH) - filter port(add, AB) == sigH.extract(0, GetSize(port(add, AB))) + filter port(add, AB) == sigH.extract(0, GetSize(port(add, AB))) filter nusers(sigH.extract_end(GetSize(port(add, AB)))) <= 1 set addAB AB optional @@ -280,7 +280,7 @@ code argD ffO ffOholdmux ffOrstmux ffOholdpol ffOrstpol sigO sigCD clock clock_p endcode code argQ ffCD ffCDholdmux ffCDholdpol ffCDrstpol sigCD clock clock_pol - if (!sigCD.empty() && + if (!sigCD.empty() && sigCD != sigO && (mul->type != \SB_MAC16 || (!param(mul, \C_REG).as_bool() && !param(mul, \D_REG).as_bool()))) { argQ = sigCD; subpattern(in_dffe); -- cgit v1.2.3 From 8cfcaf108e7fd7f538ab2939032f061dc134489b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 19 Sep 2019 22:48:57 -0700 Subject: Disable support for SB_MAC16 reset since it is async --- passes/pmgen/ice40_dsp.cc | 6 +++--- passes/pmgen/ice40_dsp.pmg | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 2d264a6d1..cff4c5ddb 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -287,9 +287,9 @@ struct Ice40DspPass : public Pass { log("cells into iCE40 DSP resources.\n"); log("Currently, only the 16x16 multiply mode is supported and not the 2 x 8x8 mode.\n"); log("\n"); - log("Pack input registers (A, B, {C,D}; with optional hold/reset), pipeline registers\n"); - log("({F,J,K,G}, H; with shared reset), output registers (O; with optional hold/reset),\n"); - log("and post-adder into the SB_MAC16 resource.\n"); + log("Pack input registers (A, B, {C,D}; with optional hold), pipeline registers\n"); + log("({F,J,K,G}, H), output registers (O; with optional hold), and post-adder into\n"); + log("into the SB_MAC16 resource.\n"); log("\n"); log("Multiply-accumulate operations using the post-adder with feedback on the {C,D}\n"); log("input will be folded into the DSP. In this scenario only, resetting the\n"); diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 09fd8406d..b4bfdce4a 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -384,6 +384,8 @@ code argQ argD endcode match ffrstmux + if false /* TODO: ice40 resets are actually async */ + if !argD.empty() select ffrstmux->type.in($mux) index port(ffrstmux, \Y) === argD @@ -487,6 +489,8 @@ code argD argQ endcode match ffrstmux + if false /* TODO: ice40 resets are actually async */ + select ffrstmux->type.in($mux) // ffrstmux output must have two users: ffrstmux and ff.D select nusers(port(ffrstmux, \Y)) == 2 -- cgit v1.2.3 From 1f64b34c64eb4177139aab7b91bd6173c33923d1 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 20 Sep 2019 10:27:17 +0200 Subject: Add "add -mod" Signed-off-by: Clifford Wolf --- passes/cmds/add.cc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'passes') diff --git a/passes/cmds/add.cc b/passes/cmds/add.cc index af6f7043d..dd05ac81f 100644 --- a/passes/cmds/add.cc +++ b/passes/cmds/add.cc @@ -105,6 +105,11 @@ struct AddPass : public Pass { log("Like 'add -input', but also connect the signal between instances of the\n"); log("selected modules.\n"); log("\n"); + log("\n"); + log(" add -mod \n"); + log("\n"); + log("Add module[s] with the specified name[s].\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { @@ -113,6 +118,7 @@ struct AddPass : public Pass { bool arg_flag_input = false; bool arg_flag_output = false; bool arg_flag_global = false; + bool mod_mode = false; int arg_width = 0; size_t argidx; @@ -133,8 +139,20 @@ struct AddPass : public Pass { arg_width = atoi(args[++argidx].c_str()); continue; } + if (arg == "-mod") { + mod_mode = true; + argidx++; + break; + } break; } + + if (mod_mode) { + for (; argidx < args.size(); argidx++) + design->addModule(RTLIL::escape_id(args[argidx])); + return; + } + extra_args(args, argidx, design); for (auto &mod : design->modules_) -- cgit v1.2.3 From a0d3ecf8c6cf4710a53fa67a4f60ef7140ee0c3a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 20 Sep 2019 08:41:28 -0700 Subject: Small cleanup --- passes/pmgen/ice40_dsp.pmg | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index b4bfdce4a..96fd8e5c9 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -1,5 +1,6 @@ pattern ice40_dsp +udata > unextend state clock state clock_pol cd_signed o_lo state sigA sigB sigCD sigH sigO @@ -27,6 +28,19 @@ match mul endmatch code sigA sigB sigH + unextend = [](const SigSpec &sig) { + int i; + for (i = GetSize(sig)-1; i > 0; i--) + if (sig[i] != sig[i-1]) + break; + // Do not remove non-const sign bit + if (sig[i].wire) + ++i; + return sig.extract(0, i); + }; + sigA = unextend(port(mul, \A)); + sigB = unextend(port(mul, \B)); + SigSpec O; if (mul->type == $mul) O = mul->getPort(\Y); @@ -36,25 +50,8 @@ code sigA sigB sigH if (GetSize(O) <= 10) reject; - sigA = port(mul, \A); - int i; - for (i = GetSize(sigA)-1; i > 0; i--) - if (sigA[i] != sigA[i-1]) - break; - // Do not remove non-const sign bit - if (sigA[i].wire) - ++i; - sigA.remove(i, GetSize(sigA)-i); - sigB = port(mul, \B); - for (i = GetSize(sigB)-1; i > 0; i--) - if (sigB[i] != sigB[i-1]) - break; - // Do not remove non-const sign bit - if (sigB[i].wire) - ++i; - sigB.remove(i, GetSize(sigB)-i); - // Only care about those bits that are used + int i; for (i = 0; i < GetSize(O); i++) { if (nusers(O[i]) <= 1) break; @@ -105,7 +102,7 @@ code argQ ffB ffBholdmux ffBrstmux ffBholdpol ffBrstpol sigB clock clock_pol } endcode -code argD ffFJKG sigH sigO clock clock_pol +code argD ffFJKG sigH clock clock_pol if (nusers(sigH) == 2 && (mul->type != \SB_MAC16 || (!param(mul, \TOP_8x8_MULT_REG).as_bool() && !param(mul, \BOT_8x8_MULT_REG).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool()))) { @@ -183,9 +180,11 @@ endcode match add if mul->type != \SB_MAC16 || (param(mul, \TOPOUTPUT_SELECT).as_int() == 3 && param(mul, \BOTOUTPUT_SELECT).as_int() == 3) + select add->type.in($add) choice AB {\A, \B} select nusers(port(add, AB)) == 2 + index port(add, AB)[0] === sigH[0] filter GetSize(port(add, AB)) <= GetSize(sigH) filter port(add, AB) == sigH.extract(0, GetSize(port(add, AB))) -- cgit v1.2.3 From 1844498c5f4f19f77919faf056b165d8b282470e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 20 Sep 2019 09:59:42 -0700 Subject: Add an overload for port/param with default value --- passes/pmgen/pmgen.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'passes') diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index 335d26f16..d5e667911 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -453,11 +453,19 @@ with open(outfile, "w") as f: print(" return sigmap(cell->getPort(portname));", file=f) print(" }", file=f) print("", file=f) + print(" SigSpec port(Cell *cell, IdString portname, const SigSpec& defval) {", file=f) + print(" return sigmap(cell->connections_.at(portname, defval));", file=f) + print(" }", file=f) + print("", file=f) print(" Const param(Cell *cell, IdString paramname) {", file=f) print(" return cell->getParam(paramname);", file=f) print(" }", file=f) print("", file=f) + print(" Const param(Cell *cell, IdString paramname, const Const& defval) {", file=f) + print(" return cell->parameters.at(paramname, defval);", file=f) + print(" }", file=f) + print("", file=f) print(" int nusers(const SigSpec &sig) {", file=f) print(" pool users;", file=f) -- cgit v1.2.3 From ed187ef1cf118727a8964e26c36530560f3e37db Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 20 Sep 2019 10:00:09 -0700 Subject: Add a xilinx_dsp_cascade matcher for PCIN -> PCOUT --- passes/pmgen/Makefile.inc | 3 +- passes/pmgen/xilinx_dsp.cc | 60 ++++------------------- passes/pmgen/xilinx_dsp.pmg | 2 +- passes/pmgen/xilinx_dsp_cascade.pmg | 94 +++++++++++++++++++++++++++++++++++++ 4 files changed, 105 insertions(+), 54 deletions(-) create mode 100644 passes/pmgen/xilinx_dsp_cascade.pmg (limited to 'passes') diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index 21f29a49a..82bb40ac8 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -22,8 +22,9 @@ $(eval $(call add_extra_objs,passes/pmgen/ice40_wrapcarry_pm.h)) # -------------------------------------- OBJS += passes/pmgen/xilinx_dsp.o -passes/pmgen/xilinx_dsp.o: passes/pmgen/xilinx_dsp_pm.h +passes/pmgen/xilinx_dsp.o: passes/pmgen/xilinx_dsp_pm.h passes/pmgen/xilinx_dsp_cascade_pm.h $(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_pm.h)) +$(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_cascade_pm.h)) # -------------------------------------- diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index abd145723..0d0c60375 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -25,6 +25,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN #include "passes/pmgen/xilinx_dsp_pm.h" +#include "passes/pmgen/xilinx_dsp_cascade_pm.h" static Cell* addDsp(Module *module) { Cell *cell = module->addCell(NEW_ID, ID(DSP48E1)); @@ -253,9 +254,9 @@ void pack_xilinx_simd(Module *module, const std::vector &selected_cells) } -void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) +void pack_xilinx_dsp(xilinx_dsp_pm &pm) { - auto &st = pm.st_xilinx_dsp; + auto &st = pm.st_xilinx_dsp_pack; #if 1 log("\n"); @@ -487,9 +488,6 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) P.append(pm.module->addWire(NEW_ID, 48-GetSize(P))); cell->setPort(ID(P), P); - bit_to_driver.insert(std::make_pair(P[0], cell)); - bit_to_driver.insert(std::make_pair(P[17], cell)); - pm.blacklist(cell); } @@ -508,7 +506,7 @@ struct XilinxDspPass : public Pass { log("Multiply-accumulate operations using the post-adder with feedback on the 'C'\n"); log("input will be folded into the DSP. In this scenario only, the 'C' input can be\n"); log("used to override the current accumulation result with a new value, which will\n"); - log("be added to the multiplier result to form the next accumulation result.\n"); + log("be added to the multiplier result to form the next accumulation result.\n"); log("\n"); log("Use of the dedicated 'PCOUT' -> 'PCIN' cascade path is detected for 'P' -> 'C'\n"); log("connections (optionally, where 'P' is right-shifted by 18-bits and used as an\n"); @@ -545,52 +543,10 @@ struct XilinxDspPass : public Pass { pack_xilinx_simd(module, module->selected_cells()); xilinx_dsp_pm pm(module, module->selected_cells()); - dict bit_to_driver; - auto f = [&bit_to_driver](xilinx_dsp_pm &pm){ pack_xilinx_dsp(bit_to_driver, pm); }; - pm.run_xilinx_dsp(f); - - auto &unextend = pm.ud_xilinx_dsp.unextend; - // Look for ability to convert C input from another DSP into PCIN - // NB: Needs to be done after pattern matcher has folded all - // $add cells into the DSP - for (auto cell : module->cells()) { - if (cell->type != ID(DSP48E1)) - continue; - if (cell->parameters.at(ID(CREG), State::S1).as_bool()) - continue; - SigSpec &opmode = cell->connections_.at(ID(OPMODE)); - if (opmode.extract(4,3) != Const::from_string("011")) - continue; - SigSpec C = unextend(pm.sigmap(cell->getPort(ID(C)))); - if (!C[0].wire) - continue; - auto it = bit_to_driver.find(C[0]); - if (it == bit_to_driver.end()) - continue; - auto driver = it->second; - - SigSpec P = driver->getPort(ID(P)); - if (GetSize(P) >= GetSize(C) && P.extract(0, GetSize(C)) == C) { - cell->setPort(ID(C), Const(0, 48)); - Wire *cascade = module->addWire(NEW_ID, 48); - driver->setPort(ID(PCOUT), cascade); - cell->setPort(ID(PCIN), cascade); - opmode[6] = State::S0; - opmode[5] = State::S0; - opmode[4] = State::S1; - bit_to_driver.erase(it); - } - else if (GetSize(P) >= GetSize(C)+17 && P.extract(17, GetSize(C)) == C) { - cell->setPort(ID(C), Const(0, 48)); - Wire *cascade = module->addWire(NEW_ID, 48); - driver->setPort(ID(PCOUT), cascade); - cell->setPort(ID(PCIN), cascade); - opmode[6] = State::S1; - opmode[5] = State::S0; - opmode[4] = State::S1; - bit_to_driver.erase(it); - } - } + pm.run_xilinx_dsp_pack(pack_xilinx_dsp); + + xilinx_dsp_cascade_pm pmc(module, module->selected_cells()); + pmc.run_xilinx_dsp_cascade(); } } } XilinxDspPass; diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 20565f47d..0ee230ccc 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,4 +1,4 @@ -pattern xilinx_dsp +pattern xilinx_dsp_pack udata > unextend state clock diff --git a/passes/pmgen/xilinx_dsp_cascade.pmg b/passes/pmgen/xilinx_dsp_cascade.pmg new file mode 100644 index 000000000..901173724 --- /dev/null +++ b/passes/pmgen/xilinx_dsp_cascade.pmg @@ -0,0 +1,94 @@ +pattern xilinx_dsp_cascade + +udata > unextend +state sigC + +code + unextend = [](const SigSpec &sig) { + int i; + for (i = GetSize(sig)-1; i > 0; i--) + if (sig[i] != sig[i-1]) + break; + // Do not remove non-const sign bit + if (sig[i].wire) + ++i; + return sig.extract(0, i); + }; +endcode + +match dsp_pcin + select dsp_pcin->type.in(\DSP48E1) + select !param(dsp_pcin, \CREG, State::S1).as_bool() + select port(dsp_pcin, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("011") + select nusers(port(dsp_pcin, \C, SigSpec())) > 1 + select nusers(port(dsp_pcin, \PCIN, SigSpec())) == 0 +endmatch + +code sigC + sigC = unextend(port(dsp_pcin, \C)); +endcode + +match dsp_pcout + select dsp_pcout->type.in(\DSP48E1) + select nusers(port(dsp_pcout, \P, SigSpec())) > 1 + select nusers(port(dsp_pcout, \PCOUT, SigSpec())) <= 1 + + index port(dsp_pcout, \P)[0] === sigC[0] + filter GetSize(port(dsp_pcin, \P)) >= GetSize(sigC) + filter port(dsp_pcout, \P).extract(0, GetSize(sigC)) == sigC + + optional +endmatch + +match dsp_pcout_shift17 + if !dsp_pcout + select dsp_pcout_shift17->type.in(\DSP48E1) + select nusers(port(dsp_pcout_shift17, \P, SigSpec())) > 1 + select nusers(port(dsp_pcout_shift17, \PCOUT, SigSpec())) <= 1 + + index port(dsp_pcout_shift17, \P)[17] === sigC[0] + filter GetSize(port(dsp_pcout_shift17, \P)) >= GetSize(sigC)+17 + filter port(dsp_pcout_shift17, \P).extract(17, GetSize(sigC)) == sigC +endmatch + +code + Cell *dsp; + if (dsp_pcout) + dsp = dsp_pcout; + else if (dsp_pcout_shift17) + dsp = dsp_pcout_shift17; + else log_abort(); + + dsp_pcin->setPort(ID(C), Const(0, 48)); + + Wire *cascade = module->addWire(NEW_ID, 48); + dsp_pcin->setPort(ID(PCIN), cascade); + dsp->setPort(ID(PCOUT), cascade); + add_siguser(cascade, dsp_pcin); + add_siguser(cascade, dsp); + + SigSpec opmode = param(dsp_pcin, \OPMODE, Const(0, 7)); + if (dsp_pcout) + opmode[6] = State::S0; + else if (dsp_pcout_shift17) + opmode[6] = State::S1; + else log_abort(); + + + opmode[5] = State::S0; + opmode[4] = State::S1; + dsp_pcin->setPort(ID(OPMODE), opmode); + + log_debug("PCOUT -> PCIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin)); + + if (nusers(port(dsp_pcin, \PCOUT, SigSpec())) > 1) { + log_debug(" Saturated PCIN/PCOUT on %s\n", log_id(dsp_pcin)); + blacklist(dsp_pcin); + } + if (nusers(port(dsp, \PCIN, SigSpec())) > 1) { + log_debug(" Saturated PCIN/PCOUT on %s\n", log_id(dsp)); + blacklist(dsp_pcout); + } + + accept; +endcode -- cgit v1.2.3 From 70c5444b25f18760781509104f4393b3d0a05fc0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 20 Sep 2019 10:07:54 -0700 Subject: Update doc --- passes/pmgen/ice40_dsp.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index cff4c5ddb..0b7ffe64b 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -288,8 +288,8 @@ struct Ice40DspPass : public Pass { log("Currently, only the 16x16 multiply mode is supported and not the 2 x 8x8 mode.\n"); log("\n"); log("Pack input registers (A, B, {C,D}; with optional hold), pipeline registers\n"); - log("({F,J,K,G}, H), output registers (O; with optional hold), and post-adder into\n"); - log("into the SB_MAC16 resource.\n"); + log("({F,J,K,G}, H), output registers (O -- full 32-bits or lower 16-bits only; with\n"); + log("optional hold), and post-adder into into the SB_MAC16 resource.\n"); log("\n"); log("Multiply-accumulate operations using the post-adder with feedback on the {C,D}\n"); log("input will be folded into the DSP. In this scenario only, resetting the\n"); -- cgit v1.2.3 From 1809f463fb235a5e4c137ee992712ecc8d235fdc Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 20 Sep 2019 12:03:10 -0700 Subject: More exceptions --- passes/pmgen/pmgen.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index d5e667911..39a09991d 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -286,7 +286,7 @@ def process_pmgfile(f, filename): block["gencode"].append(rewrite_cpp(l.rstrip())) break - assert False + raise RuntimeError("'%s' statement not recognised on line %d" % (a[0], linenr)) if block["optional"]: assert not block["semioptional"] @@ -328,7 +328,7 @@ def process_pmgfile(f, filename): blocks.append(block) continue - assert False + raise RuntimeError("'%s' command not recognised" % cmd) for fn in pmgfiles: with open(fn, "r") as f: -- cgit v1.2.3 From d88903e6108f8afc8e74ee3d3e942b98c21e1ae9 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 20 Sep 2019 12:03:25 -0700 Subject: Cleanup xilinx_dsp --- passes/pmgen/xilinx_dsp.pmg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 0ee230ccc..7d34c6a78 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -2,7 +2,7 @@ pattern xilinx_dsp_pack udata > unextend state clock -state sigA sigffAcemuxY sigB sigffBcemuxY sigC sigffCcemuxY sigD sigffDcemuxY sigM sigP +state sigA sigB sigC sigD sigM sigP state postAddAB postAddMuxAB state ffA1cepol ffA2cepol ffADcepol ffB1cepol ffB2cepol ffCcepol ffDcepol ffMcepol ffPcepol state ffArstpol ffADrstpol ffBrstpol ffCrstpol ffDrstpol ffMrstpol ffPrstpol -- cgit v1.2.3 From 1b892ca1be15864830253c2f67fd831de39020bd Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 20 Sep 2019 12:03:45 -0700 Subject: Cleanup ice40_dsp.pmg --- passes/pmgen/ice40_dsp.pmg | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 96fd8e5c9..19ee9054b 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -136,11 +136,9 @@ code argD ffFJKG sigH clock clock_pol clock = dffclock; clock_pol = dffclock_pol; sigH = dffQ; - } - } - if (0) { -reject_ffFJKG: ; +reject_ffFJKG: ; + } } endcode @@ -168,11 +166,9 @@ code argD ffH sigH sigO clock clock_pol clock = dffclock; clock_pol = dffclock_pol; sigH = dffQ; - } - } - if (0) { -reject_ffH: ; +reject_ffH: ; + } } sigO = sigH; @@ -312,11 +308,9 @@ code argQ ffCD ffCDholdmux ffCDholdpol ffCDrstpol sigCD clock clock_pol clock = dffclock; clock_pol = dffclock_pol; sigCD = dffD; - } - } - if (0) { -reject_ffCD: ; +reject_ffCD: ; + } } endcode -- cgit v1.2.3 From b0ad2592befb1a5b5a41319f6d75773aea202173 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 20 Sep 2019 12:04:16 -0700 Subject: Run until convergence --- passes/pmgen/xilinx_dsp.cc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 0d0c60375..7530eb5ad 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -24,6 +24,8 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +bool did_something; + #include "passes/pmgen/xilinx_dsp_pm.h" #include "passes/pmgen/xilinx_dsp_cascade_pm.h" @@ -509,7 +511,7 @@ struct XilinxDspPass : public Pass { log("be added to the multiplier result to form the next accumulation result.\n"); log("\n"); log("Use of the dedicated 'PCOUT' -> 'PCIN' cascade path is detected for 'P' -> 'C'\n"); - log("connections (optionally, where 'P' is right-shifted by 18-bits and used as an\n"); + log("connections (optionally, where 'P' is right-shifted by 17-bits and used as an\n"); log("input to the post-adder -- a pattern common for summing partial products to\n"); log("implement wide multipliers).\n"); log("\n"); @@ -545,8 +547,12 @@ struct XilinxDspPass : public Pass { xilinx_dsp_pm pm(module, module->selected_cells()); pm.run_xilinx_dsp_pack(pack_xilinx_dsp); - xilinx_dsp_cascade_pm pmc(module, module->selected_cells()); - pmc.run_xilinx_dsp_cascade(); + do { + did_something = false; + xilinx_dsp_cascade_pm pmc(module, module->selected_cells()); + pmc.run_xilinx_dsp_cascadeP(); + pmc.run_xilinx_dsp_cascadeAB(); + } while (did_something); } } } XilinxDspPass; -- cgit v1.2.3 From 0bca366bcd0f936bc232cf869ef13818572664f8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 20 Sep 2019 12:07:14 -0700 Subject: WIP for xiinx_dsp_cascadeAB --- passes/pmgen/xilinx_dsp_cascade.pmg | 502 +++++++++++++++++++++++++++++++++++- 1 file changed, 499 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp_cascade.pmg b/passes/pmgen/xilinx_dsp_cascade.pmg index 901173724..996a3b80f 100644 --- a/passes/pmgen/xilinx_dsp_cascade.pmg +++ b/passes/pmgen/xilinx_dsp_cascade.pmg @@ -1,4 +1,4 @@ -pattern xilinx_dsp_cascade +pattern xilinx_dsp_cascadeP udata > unextend state sigC @@ -33,7 +33,7 @@ match dsp_pcout select nusers(port(dsp_pcout, \P, SigSpec())) > 1 select nusers(port(dsp_pcout, \PCOUT, SigSpec())) <= 1 - index port(dsp_pcout, \P)[0] === sigC[0] + index port(dsp_pcout, \P)[0] === sigC[0] filter GetSize(port(dsp_pcin, \P)) >= GetSize(sigC) filter port(dsp_pcout, \P).extract(0, GetSize(sigC)) == sigC @@ -46,7 +46,7 @@ match dsp_pcout_shift17 select nusers(port(dsp_pcout_shift17, \P, SigSpec())) > 1 select nusers(port(dsp_pcout_shift17, \PCOUT, SigSpec())) <= 1 - index port(dsp_pcout_shift17, \P)[17] === sigC[0] + index port(dsp_pcout_shift17, \P)[17] === sigC[0] filter GetSize(port(dsp_pcout_shift17, \P)) >= GetSize(sigC)+17 filter port(dsp_pcout_shift17, \P).extract(17, GetSize(sigC)) == sigC endmatch @@ -90,5 +90,501 @@ code blacklist(dsp_pcout); } + did_something = true; accept; endcode + +// ########## + +pattern xilinx_dsp_cascadeAB + +udata > unextend +state clock +state sigA sigB + +state ffA1cepol ffA2cepol ffB1cepol ffB2cepol +state ffArstpol ffBrstpol + +state ffA1 ffA1cemux ffA1rstmux ffA2 ffA2cemux ffA2rstmux +state ffB1 ffB1cemux ffB1rstmux ffB2 ffB2cemux ffB2rstmux + +// subpattern +state argQ argD +state ffcepol ffrstpol +state ffoffset +udata dffD dffQ +udata dffclock +udata dff dffcemux dffrstmux +udata dffcepol dffrstpol + +code + unextend = [](const SigSpec &sig) { + int i; + for (i = GetSize(sig)-1; i > 0; i--) + if (sig[i] != sig[i-1]) + break; + // Do not remove non-const sign bit + if (sig[i].wire) + ++i; + return sig.extract(0, i); + }; +endcode + +match dspD + select dspD->type.in(\DSP48E1) + select (param(dspD, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && nusers(port(dspD, \A, SigSpec())) > 1 && nusers(port(dspD, \ACIN, SigSpec())) == 0) || (param(dspD, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && nusers(port(dspD, \B, SigSpec())) > 1 && nusers(port(dspD, \BCIN, SigSpec())) == 0) +endmatch + +code sigA sigB + if (param(dspD, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT") + sigA = unextend(port(dspD, \A)); + if (param(dspD, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT") + sigB = unextend(port(dspD, \B)); +endcode + +code argQ ffA2 ffA2cemux ffA2rstmux ffA2cepol ffArstpol ffA1 ffA1cemux ffA1rstmux ffA1cepol sigA clock + if (!sigA.empty()) { + argQ = sigA; + subpattern(in_dffe); + if (dff) { + ffA2 = dff; + clock = dffclock; + if (dffrstmux) { + ffA2rstmux = dffrstmux; + ffArstpol = dffrstpol; + } + if (dffcemux) { + ffA2cemux = dffcemux; + ffA2cepol = dffcepol; + } + sigA = dffD; + + // Now attempt to match A1 + argQ = sigA; + subpattern(in_dffe); + if (dff) { + if ((ffA2rstmux != nullptr) ^ (dffrstmux != nullptr)) + goto reject_ffA1; + if (dffrstmux) { + if (ffArstpol != dffrstpol) + goto reject_ffA1; + if (port(ffA2rstmux, \S) != port(dffrstmux, \S)) + goto reject_ffA1; + ffA1rstmux = dffrstmux; + } + + ffA1 = dff; + clock = dffclock; + + if (dffcemux) { + ffA1cemux = dffcemux; + ffA1cepol = dffcepol; + } + sigA = dffD; + +reject_ffA1: ; + } + } + } +endcode + +match dspQA2 + if ffA1 + select dspQA2->type.in(\DSP48E1) + select param(dspQA2, \A_REG, 2).as_int() == 2 + select nusers(port(dspQA2, \A, SigSpec())) > 1 + select nusers(port(dspQA2, \ACOUT, SigSpec())) == 0 + slice offset GetSize(port(dspQA2, \A)) + index port(dspQA2, \A)[offset] === sigA[0] + index port(dspQA2, \CLK) === port(dspD, \CLK) + + // Check that the rest of sigA is present + filter GetSize(port(dspQA2, \A)) >= offset + GetSize(sigA) + filter port(dspQA2, \A).extract(offset, GetSize(sigA)) == sigA + + optional +endmatch + +code + if (dspQA2) { + // Check CE and RST are compatible + if ((ffA1cemux != nullptr) == port(dspQA2, \CEA1, State::S1).is_fully_const()) + reject; + if ((ffA2cemux != nullptr) == port(dspQA2, \CEA2, State::S1).is_fully_const()) + reject; + if ((ffA1rstmux != nullptr) == port(dspQA2, \RSTA, State::S0).is_fully_const()) + reject; + if ((ffA2rstmux != nullptr) == port(dspQA2, \RSTA, State::S0).is_fully_const()) + reject; + + if (ffA1cemux) { + if (port(dspQA2, \CEA1) != port(ffA1cemux, \S)) + reject; + // TODO: Support inversions + if (!ffA1cepol) + reject; + } + if (ffA2cemux) { + if (port(dspQA2, \CEA2) != port(ffA2cemux, \S)) + reject; + // TODO: Support inversions + if (!ffA2cepol) + reject; + } + if (ffA1rstmux) { + if (port(dspQA2, \RSTA) != port(ffA1rstmux, \S)) + reject; + // TODO: Support inversions + if (!ffArstpol) + reject; + } + if (ffA2rstmux) { + if (port(dspQA2, \RSTA) != port(ffA2rstmux, \S)) + reject; + // TODO: Support inversions + if (!ffArstpol) + reject; + } + } +endcode + +match dspQA1 + if !dspQA1 && !ffA1 + if ffA2 + select dspQA1->type.in(\DSP48E1) + select param(dspQA1, \A_REG, 2).as_int() == 1 + select nusers(port(dspQA1, \A, SigSpec())) > 1 + select nusers(port(dspQA1, \ACOUT, SigSpec())) == 0 + slice offset GetSize(port(dspQA1, \A)) + index port(dspQA1, \A)[offset] === sigA[0] + index port(dspQA1, \CLK) === port(dspD, \CLK) + + // Check that the rest of sigA is present + filter GetSize(port(dspQA1, \A)) >= offset + GetSize(sigA) + filter port(dspQA1, \A).extract(offset, GetSize(sigA)) == sigA + + optional +endmatch + +code + if (dspQA1) { + // Check CE and RST are compatible + if ((ffA2cemux != NULL) == port(dspQA1, \CEA2, State::S1).is_fully_const()) + reject; + if ((ffA2rstmux != NULL) == port(dspQA1, \RSTA, State::S0).is_fully_const()) + reject; + + if (!ffA2cepol || !ffArstpol) + reject; + + if (ffA2cemux) { + if (port(dspQA1, \CEA2) != port(ffA2cemux, \S)) + reject; + // TODO: Support inversions + if (!ffA2cepol) + reject; + } + if (ffA2rstmux) { + if (port(dspQA1, \RSTA) != port(ffA2rstmux, \S)) + reject; + // TODO: Support inversions + if (!ffArstpol) + reject; + } + } +endcode + +code argQ ffB2 ffB2cemux ffB2rstmux ffB2cepol ffBrstpol ffB1 ffB1cemux ffB1rstmux ffB1cepol sigB clock + if (!sigB.empty()) { + argQ = sigB; + subpattern(in_dffe); + if (dff) { + ffB2 = dff; + clock = dffclock; + if (dffrstmux) { + ffB2rstmux = dffrstmux; + ffBrstpol = dffrstpol; + } + if (dffcemux) { + ffB2cemux = dffcemux; + ffB2cepol = dffcepol; + } + sigB = dffD; + + // Now attempt to match B1 + argQ = sigB; + subpattern(in_dffe); + if (dff) { + if ((ffB2rstmux != nullptr) ^ (dffrstmux != nullptr)) + goto reject_ffB1; + if (dffrstmux) { + if (ffBrstpol != dffrstpol) + goto reject_ffB1; + if (port(ffB2rstmux, \S) != port(dffrstmux, \S)) + goto reject_ffB1; + ffB1rstmux = dffrstmux; + } + + ffB1 = dff; + clock = dffclock; + + if (dffcemux) { + ffB1cemux = dffcemux; + ffB1cepol = dffcepol; + } + sigB = dffD; + +reject_ffB1: ; + } + } + } +endcode + +match dspQB2 + if ffB1 + select dspQB2->type.in(\DSP48E1) + select param(dspQB2, \B_REG, 2).as_int() == 2 + select nusers(port(dspQB2, \B, SigSpec())) > 1 + select nusers(port(dspQB2, \BCOUT, SigSpec())) == 0 + slice offset GetSize(port(dspQB2, \B)) + index port(dspQB2, \B)[offset] === sigB[0] + index port(dspQB2, \CLK) === port(dspD, \CLK) + + // Check that the rest of sigB is present + filter GetSize(port(dspQB2, \B)) >= offset + GetSize(sigB) + filter port(dspQB2, \B).extract(offset, GetSize(sigB)) == sigB + + optional +endmatch + +code + if (dspQB2) { + // Check CE and RST are compatible + if ((ffB1cemux != nullptr) == port(dspQB2, \CEB1, State::S1).is_fully_const()) + reject; + if ((ffB2cemux != NULL) == port(dspQB2, \CEB2, State::S1).is_fully_const()) + reject; + if ((ffB1rstmux != NULL) == port(dspQB2, \RSTB, State::S0).is_fully_const()) + reject; + if ((ffB2rstmux != NULL) == port(dspQB2, \RSTB, State::S0).is_fully_const()) + reject; + + if (ffB1cemux) { + if (port(dspQB2, \CEB1) != port(ffB1cemux, \S)) + reject; + // TODO: Support inversions + if (!ffB1cepol) + reject; + } + if (ffB2cemux) { + if (port(dspQB2, \CEB2) != port(ffB2cemux, \S)) + reject; + // TODO: Support inversions + if (!ffB2cepol) + reject; + } + if (ffB2rstmux) { + if (port(dspQB2, \RSTB) != port(ffB2rstmux, \S)) + reject; + // TODO: Support inversions + if (!ffBrstpol) + reject; + } + } +endcode + +match dspQB1 + if !dspQB1 && !ffB1 + if ffB2 + select dspQB1->type.in(\DSP48E1) + select param(dspQB1, \B_REG, 2).as_int() >= 1 + select nusers(port(dspQB1, \B, SigSpec())) > 1 + select nusers(port(dspQB1, \BCOUT, SigSpec())) == 0 + slice offset GetSize(port(dspQB1, \B)) + index port(dspQB1, \B)[offset] === sigB[0] + index port(dspQB1, \CLK) === port(dspD, \CLK) + + // Check that the rest of sigB is present + filter GetSize(port(dspQB1, \B)) >= offset + GetSize(sigB) + filter port(dspQB1, \B).extract(offset, GetSize(sigB)) == sigB + + optional +endmatch + +code + if (dspQB1) { + // Check CE and RST are compatible + if ((ffB2cemux != NULL) != port(dspQB1, \CEB2, State::S1).is_fully_const()) + reject; + if ((ffB2rstmux != NULL) != port(dspQB1, \RSTB, State::S0).is_fully_const()) + reject; + + if (!ffA2cepol || !ffArstpol) + reject; + + if (ffA2cemux) { + if (port(dspQB1, \CEB2) != port(ffB2cemux, \S)) + reject; + // TODO: Support inversions + if (!ffA2cepol) + reject; + } + if (ffA2rstmux) { + if (port(dspQB1, \RSTB) != port(ffB2rstmux, \S)) + reject; + // TODO: Support inversions + if (!ffArstpol) + reject; + } + } +endcode + +code + if (dspQA1 || dspQA2) { + dspD->setParam(\A_INPUT, Const("CASCADE")); + dspD->setPort(\A, Const(0, 30)); + + Wire *cascade = module->addWire(NEW_ID, 30); + if (dspQA1) { + dspQA1->setParam(\ACASCREG, 1); + dspQA1->setPort(\ACOUT, cascade); + log_debug("ACOUT -> ACIN cascade for %s -> %s\n", log_id(dspQA1), log_id(dspD)); + } + else if (dspQA2) { + dspQA2->setParam(\ACASCREG, 2); + dspQA2->setPort(\ACOUT, cascade); + log_debug("ACOUT -> ACIN cascade for %s -> %s\n", log_id(dspQA2), log_id(dspD)); + } + else + log_abort(); + + dspD->setPort(\ACIN, cascade); + did_something = true; + } + if (dspQB1 || dspQB2) { + dspD->setParam(\B_INPUT, Const("CASCADE")); + dspD->setPort(\B, Const(0, 18)); + + Wire *cascade = module->addWire(NEW_ID, 18); + if (dspQB1) { + dspQB1->setParam(\BCASCREG, 1); + dspQB1->setPort(\BCOUT, cascade); + log_debug("BCOUT -> BCIN cascade for %s -> %s\n", log_id(dspQB1), log_id(dspD)); + } + else if (dspQB2) { + dspQB2->setParam(\BCASCREG, 2); + dspQB2->setPort(\BCOUT, cascade); + log_debug("BCOUT -> BCIN cascade for %s -> %s\n", log_id(dspQB2), log_id(dspD)); + } + else + log_abort(); + + dspD->setPort(\BCIN, cascade); + did_something = true; + } + + accept; +endcode + + +// ####################### + +subpattern in_dffe +arg argD argQ clock + +code + dff = nullptr; + for (auto c : argQ.chunks()) { + if (!c.wire) + reject; + if (c.wire->get_bool_attribute(\keep)) + reject; + } +endcode + +match ff + select ff->type.in($dff) + // DSP48E1 does not support clock inversion + select param(ff, \CLK_POLARITY).as_bool() + + slice offset GetSize(port(ff, \D)) + index port(ff, \Q)[offset] === argQ[0] + + // Check that the rest of argQ is present + filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ) + filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ + + set ffoffset offset +endmatch + +code argQ argD +{ + if (clock != SigBit() && port(ff, \CLK) != clock) + reject; + + SigSpec Q = port(ff, \Q); + dff = ff; + dffclock = port(ff, \CLK); + dffD = argQ; + argD = port(ff, \D); + argQ = Q; + dffD.replace(argQ, argD); + // Only search for ffrstmux if dffD only + // has two (ff, ffrstmux) users + if (nusers(dffD) > 2) + argD = SigSpec(); +} +endcode + +match ffrstmux + if !argD.empty() + select ffrstmux->type.in($mux) + index port(ffrstmux, \Y) === argD + + choice BA {\B, \A} + // DSP48E1 only supports reset to zero + select port(ffrstmux, BA).is_fully_zero() + + define pol (BA == \B) + set ffrstpol pol + semioptional +endmatch + +code argD + if (ffrstmux) { + dffrstmux = ffrstmux; + dffrstpol = ffrstpol; + argD = port(ffrstmux, ffrstpol ? \A : \B); + dffD.replace(port(ffrstmux, \Y), argD); + + // Only search for ffcemux if argQ has at + // least 3 users (ff, , ffrstmux) and + // dffD only has two (ff, ffrstmux) + if (!(nusers(argQ) >= 3 && nusers(dffD) == 2)) + argD = SigSpec(); + } + else + dffrstmux = nullptr; +endcode + +match ffcemux + if !argD.empty() + select ffcemux->type.in($mux) + index port(ffcemux, \Y) === argD + choice AB {\A, \B} + index port(ffcemux, AB) === argQ + define pol (AB == \A) + set ffcepol pol + semioptional +endmatch + +code argD + if (ffcemux) { + dffcemux = ffcemux; + dffcepol = ffcepol; + argD = port(ffcemux, ffcepol ? \B : \A); + dffD.replace(port(ffcemux, \Y), argD); + } + else + dffcemux = nullptr; +endcode -- cgit v1.2.3 From eb597431f03cb402db4fc8a514c031efc29e6580 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 20 Sep 2019 12:18:37 -0700 Subject: Do not run xilinx_dsp_cascadeAB for now --- passes/pmgen/xilinx_dsp.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 7530eb5ad..4790cc69d 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -551,7 +551,8 @@ struct XilinxDspPass : public Pass { did_something = false; xilinx_dsp_cascade_pm pmc(module, module->selected_cells()); pmc.run_xilinx_dsp_cascadeP(); - pmc.run_xilinx_dsp_cascadeAB(); + //pmc.run_xilinx_dsp_cascadeAB(); + break; } while (did_something); } } -- cgit v1.2.3 From 95644b00cb7544bb284f8071c5a2da70f3899b7c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 20 Sep 2019 12:37:29 -0700 Subject: OPMODE is port not param --- passes/pmgen/xilinx_dsp_cascade.pmg | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp_cascade.pmg b/passes/pmgen/xilinx_dsp_cascade.pmg index 996a3b80f..19fe48bba 100644 --- a/passes/pmgen/xilinx_dsp_cascade.pmg +++ b/passes/pmgen/xilinx_dsp_cascade.pmg @@ -67,17 +67,16 @@ code add_siguser(cascade, dsp_pcin); add_siguser(cascade, dsp); - SigSpec opmode = param(dsp_pcin, \OPMODE, Const(0, 7)); + SigSpec opmode = port(dsp_pcin, \OPMODE, Const(0, 7)); if (dsp_pcout) opmode[6] = State::S0; else if (dsp_pcout_shift17) opmode[6] = State::S1; else log_abort(); - opmode[5] = State::S0; opmode[4] = State::S1; - dsp_pcin->setPort(ID(OPMODE), opmode); + dsp_pcin->setPort(\OPMODE, opmode); log_debug("PCOUT -> PCIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin)); @@ -196,7 +195,7 @@ match dspQA2 select nusers(port(dspQA2, \ACOUT, SigSpec())) == 0 slice offset GetSize(port(dspQA2, \A)) index port(dspQA2, \A)[offset] === sigA[0] - index port(dspQA2, \CLK) === port(dspD, \CLK) + index port(dspQA2, \CLK, State::S0) === port(dspD, \CLK, State::S0) // Check that the rest of sigA is present filter GetSize(port(dspQA2, \A)) >= offset + GetSize(sigA) @@ -257,7 +256,7 @@ match dspQA1 select nusers(port(dspQA1, \ACOUT, SigSpec())) == 0 slice offset GetSize(port(dspQA1, \A)) index port(dspQA1, \A)[offset] === sigA[0] - index port(dspQA1, \CLK) === port(dspD, \CLK) + index port(dspQA1, \CLK, State::S0) === port(dspD, \CLK, State::S0) // Check that the rest of sigA is present filter GetSize(port(dspQA1, \A)) >= offset + GetSize(sigA) @@ -348,7 +347,7 @@ match dspQB2 select nusers(port(dspQB2, \BCOUT, SigSpec())) == 0 slice offset GetSize(port(dspQB2, \B)) index port(dspQB2, \B)[offset] === sigB[0] - index port(dspQB2, \CLK) === port(dspD, \CLK) + index port(dspQB2, \CLK, State::S0) === port(dspD, \CLK, State::S0) // Check that the rest of sigB is present filter GetSize(port(dspQB2, \B)) >= offset + GetSize(sigB) @@ -402,7 +401,7 @@ match dspQB1 select nusers(port(dspQB1, \BCOUT, SigSpec())) == 0 slice offset GetSize(port(dspQB1, \B)) index port(dspQB1, \B)[offset] === sigB[0] - index port(dspQB1, \CLK) === port(dspD, \CLK) + index port(dspQB1, \CLK, State::S0) === port(dspD, \CLK, State::S0) // Check that the rest of sigB is present filter GetSize(port(dspQB1, \B)) >= offset + GetSize(sigB) -- cgit v1.2.3 From d122083a112d51ba0d91e44c37b1d4d9d11080aa Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 20 Sep 2019 12:42:28 -0700 Subject: Output pattern matcher items as log_debug() --- passes/pmgen/ice40_dsp.cc | 24 +++++++++++------------- passes/pmgen/xilinx_dsp.cc | 34 ++++++++++++++++------------------ 2 files changed, 27 insertions(+), 31 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 0b7ffe64b..641efe076 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -29,21 +29,19 @@ void create_ice40_dsp(ice40_dsp_pm &pm) { auto &st = pm.st_ice40_dsp; -#if 1 - log("\n"); - log("ffA: %s %s %s\n", log_id(st.ffA, "--"), log_id(st.ffAholdmux, "--"), log_id(st.ffArstmux, "--")); - log("ffB: %s %s %s\n", log_id(st.ffB, "--"), log_id(st.ffBholdmux, "--"), log_id(st.ffBrstmux, "--")); - log("ffCD: %s %s\n", log_id(st.ffCD, "--"), log_id(st.ffCDholdmux, "--")); - log("mul: %s\n", log_id(st.mul, "--")); - log("ffFJKG: %s\n", log_id(st.ffFJKG, "--")); - log("ffH: %s\n", log_id(st.ffH, "--")); - log("add: %s\n", log_id(st.add, "--")); - log("mux: %s\n", log_id(st.mux, "--")); - log("ffO: %s %s %s\n", log_id(st.ffO, "--"), log_id(st.ffOholdmux, "--"), log_id(st.ffOrstmux, "--")); -#endif - log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(st.mul)); + log_debug("\n"); + log_debug("ffA: %s %s %s\n", log_id(st.ffA, "--"), log_id(st.ffAholdmux, "--"), log_id(st.ffArstmux, "--")); + log_debug("ffB: %s %s %s\n", log_id(st.ffB, "--"), log_id(st.ffBholdmux, "--"), log_id(st.ffBrstmux, "--")); + log_debug("ffCD: %s %s\n", log_id(st.ffCD, "--"), log_id(st.ffCDholdmux, "--")); + log_debug("mul: %s\n", log_id(st.mul, "--")); + log_debug("ffFJKG: %s\n", log_id(st.ffFJKG, "--")); + log_debug("ffH: %s\n", log_id(st.ffH, "--")); + log_debug("add: %s\n", log_id(st.add, "--")); + log_debug("mux: %s\n", log_id(st.mux, "--")); + log_debug("ffO: %s %s %s\n", log_id(st.ffO, "--"), log_id(st.ffOholdmux, "--"), log_id(st.ffOrstmux, "--")); + if (GetSize(st.sigA) > 16) { log(" input A (%s) is too large (%d > 16).\n", log_signal(st.sigA), GetSize(st.sigA)); return; diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 4790cc69d..1612b66ec 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -260,26 +260,24 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) { auto &st = pm.st_xilinx_dsp_pack; -#if 1 - log("\n"); - log("preAdd: %s\n", log_id(st.preAdd, "--")); - log("ffAD: %s %s %s\n", log_id(st.ffAD, "--"), log_id(st.ffADcemux, "--"), log_id(st.ffADrstmux, "--")); - log("ffA2: %s %s %s\n", log_id(st.ffA2, "--"), log_id(st.ffA2cemux, "--"), log_id(st.ffA2rstmux, "--")); - log("ffA1: %s %s %s\n", log_id(st.ffA1, "--"), log_id(st.ffA1cemux, "--"), log_id(st.ffA1rstmux, "--")); - log("ffB2: %s %s %s\n", log_id(st.ffB2, "--"), log_id(st.ffB2cemux, "--"), log_id(st.ffB2rstmux, "--")); - log("ffB1: %s %s %s\n", log_id(st.ffB1, "--"), log_id(st.ffB1cemux, "--"), log_id(st.ffB1rstmux, "--")); - log("ffC: %s %s %s\n", log_id(st.ffC, "--"), log_id(st.ffCcemux, "--"), log_id(st.ffCrstmux, "--")); - log("ffD: %s %s %s\n", log_id(st.ffD, "--"), log_id(st.ffDcemux, "--"), log_id(st.ffDrstmux, "--")); - log("dsp: %s\n", log_id(st.dsp, "--")); - log("ffM: %s %s %s\n", log_id(st.ffM, "--"), log_id(st.ffMcemux, "--"), log_id(st.ffMrstmux, "--")); - log("postAdd: %s\n", log_id(st.postAdd, "--")); - log("postAddMux: %s\n", log_id(st.postAddMux, "--")); - log("ffP: %s %s %s\n", log_id(st.ffP, "--"), log_id(st.ffPcemux, "--"), log_id(st.ffPrstmux, "--")); - log("overflow: %s\n", log_id(st.overflow, "--")); -#endif - log("Analysing %s.%s for Xilinx DSP packing.\n", log_id(pm.module), log_id(st.dsp)); + log_debug("\n"); + log_debug("preAdd: %s\n", log_id(st.preAdd, "--")); + log_debug("ffAD: %s %s %s\n", log_id(st.ffAD, "--"), log_id(st.ffADcemux, "--"), log_id(st.ffADrstmux, "--")); + log_debug("ffA2: %s %s %s\n", log_id(st.ffA2, "--"), log_id(st.ffA2cemux, "--"), log_id(st.ffA2rstmux, "--")); + log_debug("ffA1: %s %s %s\n", log_id(st.ffA1, "--"), log_id(st.ffA1cemux, "--"), log_id(st.ffA1rstmux, "--")); + log_debug("ffB2: %s %s %s\n", log_id(st.ffB2, "--"), log_id(st.ffB2cemux, "--"), log_id(st.ffB2rstmux, "--")); + log_debug("ffB1: %s %s %s\n", log_id(st.ffB1, "--"), log_id(st.ffB1cemux, "--"), log_id(st.ffB1rstmux, "--")); + log_debug("ffC: %s %s %s\n", log_id(st.ffC, "--"), log_id(st.ffCcemux, "--"), log_id(st.ffCrstmux, "--")); + log_debug("ffD: %s %s %s\n", log_id(st.ffD, "--"), log_id(st.ffDcemux, "--"), log_id(st.ffDrstmux, "--")); + log_debug("dsp: %s\n", log_id(st.dsp, "--")); + log_debug("ffM: %s %s %s\n", log_id(st.ffM, "--"), log_id(st.ffMcemux, "--"), log_id(st.ffMrstmux, "--")); + log_debug("postAdd: %s\n", log_id(st.postAdd, "--")); + log_debug("postAddMux: %s\n", log_id(st.postAddMux, "--")); + log_debug("ffP: %s %s %s\n", log_id(st.ffP, "--"), log_id(st.ffPcemux, "--"), log_id(st.ffPrstmux, "--")); + log_debug("overflow: %s\n", log_id(st.overflow, "--")); + Cell *cell = st.dsp; if (st.preAdd) { -- cgit v1.2.3 From 53817b85753deb3dc5647414de67de1373798049 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 20 Sep 2019 14:21:22 -0700 Subject: Use new port/param overload in pmg --- passes/pmgen/ice40_dsp.pmg | 4 ++-- passes/pmgen/xilinx_dsp.cc | 2 +- passes/pmgen/xilinx_dsp.pmg | 8 ++++---- passes/pmgen/xilinx_srl.pmg | 30 +++++++++++++++--------------- 4 files changed, 22 insertions(+), 22 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 19ee9054b..046aae9e2 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -225,9 +225,9 @@ endcode code argD ffO ffOholdmux ffOrstmux ffOholdpol ffOrstpol sigO sigCD clock clock_pol cd_signed o_lo if (mul->type != \SB_MAC16 || // Ensure that register is not already used - ((mul->parameters.at(\TOPOUTPUT_SELECT, 0).as_int() != 1 && mul->parameters.at(\BOTOUTPUT_SELECT, 0).as_int() != 1) && + ((param(mul, \TOPOUTPUT_SELECT, 0).as_int() != 1 && param(mul, \BOTOUTPUT_SELECT, 0).as_int() != 1) && // Ensure that OLOADTOP/OLOADBOT is unused or zero - (mul->connections_.at(\OLOADTOP, State::S0).is_fully_zero() && mul->connections_.at(\OLOADBOT, State::S0).is_fully_zero()))) { + (port(mul, \OLOADTOP, State::S0).is_fully_zero() && port(mul, \OLOADBOT, State::S0).is_fully_zero()))) { dff = nullptr; diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 1612b66ec..9d0a77e2b 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -290,7 +290,7 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) st.sigD.extend_u0(25, D_SIGNED); cell->setPort(ID(A), st.sigA); cell->setPort(ID(D), st.sigD); - cell->connections_.at(ID(INMODE)) = Const::from_string("00100"); + cell->setPort(ID(INMODE), Const::from_string("00100")); if (st.ffAD) { if (st.ffADcemux) { diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 7d34c6a78..bb29bdd99 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -42,7 +42,7 @@ code sigA sigB sigC sigD sigM sigD = dsp->connections_.at(\D, SigSpec()); SigSpec P = port(dsp, \P); - if (dsp->parameters.at(\USE_MULT, Const("MULTIPLY")).decode_string() == "MULTIPLY") { + if (param(dsp, \USE_MULT, Const("MULTIPLY")).decode_string() == "MULTIPLY") { // Only care about those bits that are used int i; for (i = 0; i < GetSize(P); i++) { @@ -79,8 +79,8 @@ endcode match preAdd if sigD.empty() || sigD.is_fully_zero() // Ensure that preAdder not already used - if dsp->parameters.at(\USE_DPORT, Const("FALSE")).decode_string() == "FALSE" - if dsp->connections_.at(\INMODE, Const(0, 5)).is_fully_zero() + if param(dsp, \USE_DPORT, Const("FALSE")).decode_string() == "FALSE" + if port(dsp, \INMODE, Const(0, 5)).is_fully_zero() select preAdd->type.in($add) // Output has to be 25 bits or less @@ -348,7 +348,7 @@ endcode match overflow if ffP - if dsp->parameters.at(\USE_PATTERN_DETECT, Const("NO_PATDET")).decode_string() == "NO_PATDET" + if param(dsp, \USE_PATTERN_DETECT, Const("NO_PATDET")).decode_string() == "NO_PATDET" select overflow->type.in($ge) select GetSize(port(overflow, \Y)) <= 48 select port(overflow, \B).is_fully_const() diff --git a/passes/pmgen/xilinx_srl.pmg b/passes/pmgen/xilinx_srl.pmg index b18119b87..535b3dfdc 100644 --- a/passes/pmgen/xilinx_srl.pmg +++ b/passes/pmgen/xilinx_srl.pmg @@ -13,9 +13,9 @@ endcode match first select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1) select !first->has_keep_attr() - select !first->type.in(\FDRE) || !first->parameters.at(\IS_R_INVERTED, State::S0).as_bool() - select !first->type.in(\FDRE) || !first->parameters.at(\IS_D_INVERTED, State::S0).as_bool() - select !first->type.in(\FDRE, \FDRE_1) || first->connections_.at(\R, State::S0).is_fully_zero() + select !first->type.in(\FDRE) || !param(first, \IS_R_INVERTED, State::S0).as_bool() + select !first->type.in(\FDRE) || !param(first, \IS_D_INVERTED, State::S0).as_bool() + select !first->type.in(\FDRE, \FDRE_1) || port(first, \R, State::S0).is_fully_zero() filter !non_first_cells.count(first) generate SigSpec C = module->addWire(NEW_ID); @@ -84,9 +84,9 @@ arg en_port match first select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1) select !first->has_keep_attr() - select !first->type.in(\FDRE) || !first->parameters.at(\IS_R_INVERTED, State::S0).as_bool() - select !first->type.in(\FDRE) || !first->parameters.at(\IS_D_INVERTED, State::S0).as_bool() - select !first->type.in(\FDRE, \FDRE_1) || first->connections_.at(\R, State::S0).is_fully_zero() + select !first->type.in(\FDRE) || !param(first, \IS_R_INVERTED, State::S0).as_bool() + select !first->type.in(\FDRE) || !param(first, \IS_D_INVERTED, State::S0).as_bool() + select !first->type.in(\FDRE, \FDRE_1) || port(first, \R, State::S0).is_fully_zero() endmatch code clk_port en_port @@ -111,10 +111,10 @@ match next index port(next, \Q) === port(first, \D) filter port(next, clk_port) == port(first, clk_port) filter en_port == IdString() || port(next, en_port) == port(first, en_port) - filter !first->type.in(\FDRE) || next->parameters.at(\IS_C_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_C_INVERTED, State::S0).as_bool() - filter !first->type.in(\FDRE) || next->parameters.at(\IS_D_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_D_INVERTED, State::S0).as_bool() - filter !first->type.in(\FDRE) || next->parameters.at(\IS_R_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_R_INVERTED, State::S0).as_bool() - filter !first->type.in(\FDRE, \FDRE_1) || next->connections_.at(\R, State::S0).is_fully_zero() + filter !first->type.in(\FDRE) || param(next, \IS_C_INVERTED, State::S0).as_bool() == param(first, \IS_C_INVERTED, State::S0).as_bool() + filter !first->type.in(\FDRE) || param(next, \IS_D_INVERTED, State::S0).as_bool() == param(first, \IS_D_INVERTED, State::S0).as_bool() + filter !first->type.in(\FDRE) || param(next, \IS_R_INVERTED, State::S0).as_bool() == param(first, \IS_R_INVERTED, State::S0).as_bool() + filter !first->type.in(\FDRE, \FDRE_1) || port(next, \R, State::S0).is_fully_zero() endmatch code @@ -138,10 +138,10 @@ match next index port(next, \Q) === port(chain.back(), \D) filter port(next, clk_port) == port(first, clk_port) filter en_port == IdString() || port(next, en_port) == port(first, en_port) - filter !first->type.in(\FDRE) || next->parameters.at(\IS_C_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_C_INVERTED, State::S0).as_bool() - filter !first->type.in(\FDRE) || next->parameters.at(\IS_D_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_D_INVERTED, State::S0).as_bool() - filter !first->type.in(\FDRE) || next->parameters.at(\IS_R_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_R_INVERTED, State::S0).as_bool() - filter !first->type.in(\FDRE, \FDRE_1) || next->connections_.at(\R, State::S0).is_fully_zero() + filter !first->type.in(\FDRE) || param(next, \IS_C_INVERTED, State::S0).as_bool() == param(first, \IS_C_INVERTED, State::S0).as_bool() + filter !first->type.in(\FDRE) || param(next, \IS_D_INVERTED, State::S0).as_bool() == param(first, \IS_D_INVERTED, State::S0).as_bool() + filter !first->type.in(\FDRE) || param(next, \IS_R_INVERTED, State::S0).as_bool() == param(first, \IS_R_INVERTED, State::S0).as_bool() + filter !first->type.in(\FDRE, \FDRE_1) || port(next, \R, State::S0).is_fully_zero() generate Cell *cell = module->addCell(NEW_ID, chain.back()->type); cell->setPort(\C, chain.back()->getPort(\C)); @@ -149,7 +149,7 @@ generate cell->setPort(\Q, chain.back()->getPort(\D)); if (cell->type == \FDRE) { if (rng(2) == 0) - cell->setPort(\R, chain.back()->connections_.at(\R, State::S0)); + cell->setPort(\R, port(chain.back(), \R, State::S0)); cell->setPort(\CE, chain.back()->getPort(\CE)); } else if (cell->type.begins_with("$_DFFE_")) -- cgit v1.2.3 From 567e5f0aa7816bf92e0f1cb885af6fa333863163 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 20 Sep 2019 17:42:36 -0700 Subject: Fix first testcase in #1391 --- passes/techmap/abc9.cc | 2 +- passes/techmap/techmap.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 7eac08d17..7715fb291 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -30,7 +30,7 @@ "&st; &if -g -K 6; &synch2; &if {W} -v; &save; &load; "\ "&mfs; &ps -l" #else -#define ABC_COMMAND_LUT "&st; &scorr; &sweep; &dc2; &st; &dch -f; &ps; &if {W} {D} -v; &mfs; &ps -l" +#define ABC_COMMAND_LUT "&st; &scorr; &sweep; &dc2; &st; &dch -f; &ps; &if {W} {D} -v -w; &mfs; &ps -l" #endif diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index cf40b2f17..3cc3edbcb 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -224,7 +224,7 @@ struct TechmapWorker for (auto bit : sigmaps.at(tpl)(it.second)) if (bit.wire != nullptr) - autopurge_tpl_bits.insert(it.second); + autopurge_tpl_bits.insert(bit); } } IdString w_name = it.second->name; -- cgit v1.2.3 From 72ce06909e87d1697ed5eac62d91db00a751a34b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 20 Sep 2019 17:48:37 -0700 Subject: Trim mismatched connection to be same (smallest) size --- passes/techmap/techmap.cc | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'passes') diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 3cc3edbcb..1d0362ad6 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -359,6 +359,12 @@ struct TechmapWorker for (auto &attr : w->attributes) { if (attr.first == ID(src)) continue; + auto lhs = GetSize(extra_connect.first); + auto rhs = GetSize(extra_connect.second); + if (lhs > rhs) + extra_connect.first.remove(rhs, lhs-rhs); + else if (rhs > lhs) + extra_connect.second.remove(lhs, rhs-lhs); module->connect(extra_connect); break; } -- cgit v1.2.3 From ec08a031b548749bc3177ed3fdddcaf463043d26 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 20 Sep 2019 17:52:23 -0700 Subject: Revert abc9.cc --- passes/techmap/abc9.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 7715fb291..7eac08d17 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -30,7 +30,7 @@ "&st; &if -g -K 6; &synch2; &if {W} -v; &save; &load; "\ "&mfs; &ps -l" #else -#define ABC_COMMAND_LUT "&st; &scorr; &sweep; &dc2; &st; &dch -f; &ps; &if {W} {D} -v -w; &mfs; &ps -l" +#define ABC_COMMAND_LUT "&st; &scorr; &sweep; &dc2; &st; &dch -f; &ps; &if {W} {D} -v; &mfs; &ps -l" #endif -- cgit v1.2.3 From 3bed4cb18a41e87e8c61f03d6e581d5c0eae3a95 Mon Sep 17 00:00:00 2001 From: "N. Engelhardt" Date: Mon, 23 Sep 2019 17:25:30 +0200 Subject: fix show command for macos --- passes/cmds/show.cc | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'passes') diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc index 2e9fc72af..a3e969ef1 100644 --- a/passes/cmds/show.cc +++ b/passes/cmds/show.cc @@ -26,6 +26,10 @@ # include #endif +#ifdef __APPLE__ +# include +#endif + #ifdef YOSYS_ENABLE_READLINE # include #endif @@ -866,7 +870,11 @@ struct ShowPass : public Pass { log_cmd_error("Shell command failed!\n"); } else if (format.empty()) { + #ifdef __APPLE__ + std::string cmd = stringf("ps -fu %d | grep -q '[ ]%s' || xdot '%s' &", getuid(), dot_file.c_str(), dot_file.c_str()); + #else std::string cmd = stringf("{ test -f '%s.pid' && fuser -s '%s.pid'; } || ( echo $$ >&3; exec xdot '%s'; ) 3> '%s.pid' &", dot_file.c_str(), dot_file.c_str(), dot_file.c_str(), dot_file.c_str()); + #endif log("Exec: %s\n", cmd.c_str()); if (run_command(cmd) != 0) log_cmd_error("Shell command failed!\n"); -- cgit v1.2.3 From a67af3d5e5fd584837f55d2d97d621299e4fdf0c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 23 Sep 2019 13:00:44 -0700 Subject: Use new port() overload once more --- passes/pmgen/xilinx_dsp.pmg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index bb29bdd99..80bf775bc 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -38,8 +38,8 @@ code sigA sigB sigC sigD sigM sigA = unextend(port(dsp, \A)); sigB = unextend(port(dsp, \B)); - sigC = dsp->connections_.at(\C, SigSpec()); - sigD = dsp->connections_.at(\D, SigSpec()); + sigC = port(dsp, \C, SigSpec()); + sigD = port(dsp, \D, SigSpec()); SigSpec P = port(dsp, \P); if (param(dsp, \USE_MULT, Const("MULTIPLY")).decode_string() == "MULTIPLY") { -- cgit v1.2.3 From d0dbbc26054d1cd7b8766e2d996196e246216e8c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 23 Sep 2019 13:26:34 -0700 Subject: Move unextend initialisation later --- passes/pmgen/xilinx_dsp_cascade.pmg | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp_cascade.pmg b/passes/pmgen/xilinx_dsp_cascade.pmg index 19fe48bba..37674efea 100644 --- a/passes/pmgen/xilinx_dsp_cascade.pmg +++ b/passes/pmgen/xilinx_dsp_cascade.pmg @@ -3,7 +3,15 @@ pattern xilinx_dsp_cascadeP udata > unextend state sigC -code +match dsp_pcin + select dsp_pcin->type.in(\DSP48E1) + select !param(dsp_pcin, \CREG, State::S1).as_bool() + select port(dsp_pcin, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("011") + select nusers(port(dsp_pcin, \C, SigSpec())) > 1 + select nusers(port(dsp_pcin, \PCIN, SigSpec())) == 0 +endmatch + +code sigC unextend = [](const SigSpec &sig) { int i; for (i = GetSize(sig)-1; i > 0; i--) @@ -14,17 +22,6 @@ code ++i; return sig.extract(0, i); }; -endcode - -match dsp_pcin - select dsp_pcin->type.in(\DSP48E1) - select !param(dsp_pcin, \CREG, State::S1).as_bool() - select port(dsp_pcin, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("011") - select nusers(port(dsp_pcin, \C, SigSpec())) > 1 - select nusers(port(dsp_pcin, \PCIN, SigSpec())) == 0 -endmatch - -code sigC sigC = unextend(port(dsp_pcin, \C)); endcode -- cgit v1.2.3 From 26a6c55665e3d7826779d27f32031e58296ed68d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 23 Sep 2019 13:27:00 -0700 Subject: Move log_debug("\n") later --- passes/pmgen/ice40_dsp.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 641efe076..f60e67158 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -31,7 +31,6 @@ void create_ice40_dsp(ice40_dsp_pm &pm) log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(st.mul)); - log_debug("\n"); log_debug("ffA: %s %s %s\n", log_id(st.ffA, "--"), log_id(st.ffAholdmux, "--"), log_id(st.ffArstmux, "--")); log_debug("ffB: %s %s %s\n", log_id(st.ffB, "--"), log_id(st.ffBholdmux, "--"), log_id(st.ffBrstmux, "--")); log_debug("ffCD: %s %s\n", log_id(st.ffCD, "--"), log_id(st.ffCDholdmux, "--")); @@ -41,6 +40,7 @@ void create_ice40_dsp(ice40_dsp_pm &pm) log_debug("add: %s\n", log_id(st.add, "--")); log_debug("mux: %s\n", log_id(st.mux, "--")); log_debug("ffO: %s %s %s\n", log_id(st.ffO, "--"), log_id(st.ffOholdmux, "--"), log_id(st.ffOrstmux, "--")); + log_debug("\n"); if (GetSize(st.sigA) > 16) { log(" input A (%s) is too large (%d > 16).\n", log_signal(st.sigA), GetSize(st.sigA)); -- cgit v1.2.3 From 15dfbc812517a284848618eb60e3f9875c2e26ce Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 23 Sep 2019 13:27:10 -0700 Subject: Separate out CREG packing into new pattern, to avoid conflict with PREG --- passes/pmgen/Makefile.inc | 3 +- passes/pmgen/xilinx_dsp.cc | 108 +++++++++++++++++++----- passes/pmgen/xilinx_dsp.pmg | 30 ++----- passes/pmgen/xilinx_dsp_CREG.pmg | 178 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 273 insertions(+), 46 deletions(-) create mode 100644 passes/pmgen/xilinx_dsp_CREG.pmg (limited to 'passes') diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index 82bb40ac8..366c37943 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -22,8 +22,9 @@ $(eval $(call add_extra_objs,passes/pmgen/ice40_wrapcarry_pm.h)) # -------------------------------------- OBJS += passes/pmgen/xilinx_dsp.o -passes/pmgen/xilinx_dsp.o: passes/pmgen/xilinx_dsp_pm.h passes/pmgen/xilinx_dsp_cascade_pm.h +passes/pmgen/xilinx_dsp.o: passes/pmgen/xilinx_dsp_pm.h passes/pmgen/xilinx_dsp_CREG_pm.h passes/pmgen/xilinx_dsp_cascade_pm.h $(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_pm.h)) +$(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_CREG_pm.h)) $(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_cascade_pm.h)) # -------------------------------------- diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 9d0a77e2b..86472feb5 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -27,6 +27,7 @@ PRIVATE_NAMESPACE_BEGIN bool did_something; #include "passes/pmgen/xilinx_dsp_pm.h" +#include "passes/pmgen/xilinx_dsp_CREG_pm.h" #include "passes/pmgen/xilinx_dsp_cascade_pm.h" static Cell* addDsp(Module *module) { @@ -63,7 +64,7 @@ static Cell* addDsp(Module *module) { return cell; } -void pack_xilinx_simd(Module *module, const std::vector &selected_cells) +void xilinx_simd_pack(Module *module, const std::vector &selected_cells) { std::deque simd12_add, simd12_sub; std::deque simd24_add, simd24_sub; @@ -255,21 +256,18 @@ void pack_xilinx_simd(Module *module, const std::vector &selected_cells) g24(simd24_sub); } - -void pack_xilinx_dsp(xilinx_dsp_pm &pm) +void xilinx_dsp_pack(xilinx_dsp_pm &pm) { auto &st = pm.st_xilinx_dsp_pack; log("Analysing %s.%s for Xilinx DSP packing.\n", log_id(pm.module), log_id(st.dsp)); - log_debug("\n"); log_debug("preAdd: %s\n", log_id(st.preAdd, "--")); log_debug("ffAD: %s %s %s\n", log_id(st.ffAD, "--"), log_id(st.ffADcemux, "--"), log_id(st.ffADrstmux, "--")); log_debug("ffA2: %s %s %s\n", log_id(st.ffA2, "--"), log_id(st.ffA2cemux, "--"), log_id(st.ffA2rstmux, "--")); log_debug("ffA1: %s %s %s\n", log_id(st.ffA1, "--"), log_id(st.ffA1cemux, "--"), log_id(st.ffA1rstmux, "--")); log_debug("ffB2: %s %s %s\n", log_id(st.ffB2, "--"), log_id(st.ffB2cemux, "--"), log_id(st.ffB2rstmux, "--")); log_debug("ffB1: %s %s %s\n", log_id(st.ffB1, "--"), log_id(st.ffB1cemux, "--"), log_id(st.ffB1rstmux, "--")); - log_debug("ffC: %s %s %s\n", log_id(st.ffC, "--"), log_id(st.ffCcemux, "--"), log_id(st.ffCrstmux, "--")); log_debug("ffD: %s %s %s\n", log_id(st.ffD, "--"), log_id(st.ffDcemux, "--"), log_id(st.ffDrstmux, "--")); log_debug("dsp: %s\n", log_id(st.dsp, "--")); log_debug("ffM: %s %s %s\n", log_id(st.ffM, "--"), log_id(st.ffMcemux, "--"), log_id(st.ffMrstmux, "--")); @@ -277,6 +275,7 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) log_debug("postAddMux: %s\n", log_id(st.postAddMux, "--")); log_debug("ffP: %s %s %s\n", log_id(st.ffP, "--"), log_id(st.ffPcemux, "--"), log_id(st.ffPrstmux, "--")); log_debug("overflow: %s\n", log_id(st.overflow, "--")); + log_debug("\n"); Cell *cell = st.dsp; @@ -426,12 +425,6 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) else cell->setParam(ID(BREG), 1); } - if (st.ffC) { - SigSpec &C = cell->connections_.at(ID(C)); - f(C, st.ffC, st.ffCcemux, st.ffCcepol, ID(CEC), st.ffCrstmux, st.ffCrstpol, ID(RSTC)); - pm.add_siguser(C, cell); - cell->setParam(ID(CREG), 1); - } if (st.ffD) { SigSpec &D = cell->connections_.at(ID(D)); f(D, st.ffD, st.ffDcemux, st.ffDcepol, ID(CED), st.ffDrstmux, st.ffDrstpol, ID(RSTD)); @@ -468,9 +461,6 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) log(" ffB1:%s", log_id(st.ffB1)); } - if (st.ffC) - log(" ffC:%s", log_id(st.ffC)); - if (st.ffD) log(" ffD:%s", log_id(st.ffD)); @@ -491,6 +481,76 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) pm.blacklist(cell); } +void xilinx_dsp_packC(xilinx_dsp_CREG_pm &pm) +{ + auto &st = pm.st_xilinx_dsp_packC; + + log_debug("Analysing %s.%s for Xilinx DSP packing (CREG).\n", log_id(pm.module), log_id(st.dsp)); + log_debug("ffC: %s %s %s\n", log_id(st.ffC, "--"), log_id(st.ffCcemux, "--"), log_id(st.ffCrstmux, "--")); + log_debug("\n"); + + Cell *cell = st.dsp; + + if (st.clock != SigBit()) + { + cell->setPort(ID(CLK), st.clock); + + auto f = [&pm,cell](SigSpec &A, Cell* ff, Cell* cemux, bool cepol, IdString ceport, Cell* rstmux, bool rstpol, IdString rstport) { + SigSpec D = ff->getPort(ID(D)); + SigSpec Q = pm.sigmap(ff->getPort(ID(Q))); + if (!A.empty()) + A.replace(Q, D); + if (rstmux) { + SigSpec Y = rstmux->getPort(ID(Y)); + SigSpec AB = rstmux->getPort(rstpol ? ID(A) : ID(B)); + if (!A.empty()) + A.replace(Y, AB); + if (rstport != IdString()) { + SigSpec S = rstmux->getPort(ID(S)); + cell->setPort(rstport, rstpol ? S : pm.module->Not(NEW_ID, S)); + } + } + else if (rstport != IdString()) + cell->setPort(rstport, State::S0); + if (cemux) { + SigSpec Y = cemux->getPort(ID(Y)); + SigSpec BA = cemux->getPort(cepol ? ID(B) : ID(A)); + SigSpec S = cemux->getPort(ID(S)); + if (!A.empty()) + A.replace(Y, BA); + cell->setPort(ceport, cepol ? S : pm.module->Not(NEW_ID, S)); + } + else + cell->setPort(ceport, State::S1); + + for (auto c : Q.chunks()) { + auto it = c.wire->attributes.find(ID(init)); + if (it == c.wire->attributes.end()) + continue; + for (int i = c.offset; i < c.offset+c.width; i++) { + log_assert(it->second[i] == State::S0 || it->second[i] == State::Sx); + it->second[i] = State::Sx; + } + } + }; + + if (st.ffC) { + SigSpec &C = cell->connections_.at(ID(C)); + f(C, st.ffC, st.ffCcemux, st.ffCcepol, ID(CEC), st.ffCrstmux, st.ffCrstpol, ID(RSTC)); + pm.add_siguser(C, cell); + cell->setParam(ID(CREG), 1); + } + + log(" clock: %s (%s)", log_signal(st.clock), "posedge"); + + if (st.ffC) + log(" ffC:%s", log_id(st.ffC)); + log("\n"); + } + + pm.blacklist(cell); +} + struct XilinxDspPass : public Pass { XilinxDspPass() : Pass("xilinx_dsp", "Xilinx: pack resources into DSPs") { } void help() YS_OVERRIDE @@ -540,17 +600,23 @@ struct XilinxDspPass : public Pass { extra_args(args, argidx, design); for (auto module : design->selected_modules()) { - pack_xilinx_simd(module, module->selected_cells()); + xilinx_simd_pack(module, module->selected_cells()); - xilinx_dsp_pm pm(module, module->selected_cells()); - pm.run_xilinx_dsp_pack(pack_xilinx_dsp); + { + xilinx_dsp_pm pm(module, module->selected_cells()); + pm.run_xilinx_dsp_pack(xilinx_dsp_pack); + } + { + xilinx_dsp_CREG_pm pm(module, module->selected_cells()); + pm.run_xilinx_dsp_packC(xilinx_dsp_packC); + } do { did_something = false; - xilinx_dsp_cascade_pm pmc(module, module->selected_cells()); - pmc.run_xilinx_dsp_cascadeP(); - //pmc.run_xilinx_dsp_cascadeAB(); - break; + xilinx_dsp_cascade_pm pm(module, module->selected_cells()); + pm.run_xilinx_dsp_cascadeP(); + //pm.run_xilinx_dsp_cascadeAB(); + break; } while (did_something); } } diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 80bf775bc..553195649 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -4,11 +4,11 @@ udata > unextend state clock state sigA sigB sigC sigD sigM sigP state postAddAB postAddMuxAB -state ffA1cepol ffA2cepol ffADcepol ffB1cepol ffB2cepol ffCcepol ffDcepol ffMcepol ffPcepol -state ffArstpol ffADrstpol ffBrstpol ffCrstpol ffDrstpol ffMrstpol ffPrstpol +state ffA1cepol ffA2cepol ffADcepol ffB1cepol ffB2cepol ffDcepol ffMcepol ffPcepol +state ffArstpol ffADrstpol ffBrstpol ffDrstpol ffMrstpol ffPrstpol state ffAD ffADcemux ffADrstmux ffA1 ffA1cemux ffA1rstmux ffA2 ffA2cemux ffA2rstmux -state ffB1 ffB1cemux ffB1rstmux ffB2 ffB2cemux ffB2rstmux ffC ffCcemux ffCrstmux +state ffB1 ffB1cemux ffB1rstmux ffB2 ffB2cemux ffB2rstmux state ffD ffDcemux ffDrstmux ffM ffMcemux ffMrstmux ffP ffPcemux ffPrstmux // subpattern @@ -24,7 +24,7 @@ match dsp select dsp->type.in(\DSP48E1) endmatch -code sigA sigB sigC sigD sigM +code sigA sigB sigC sigD sigM clock unextend = [](const SigSpec &sig) { int i; for (i = GetSize(sig)-1; i > 0; i--) @@ -54,6 +54,8 @@ code sigA sigB sigC sigD sigM } else sigM = P; + + clock = port(dsp, \CLK, SigBit()); endcode code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock @@ -326,26 +328,6 @@ code sigC sigC = port(postAddMux, postAddMuxAB == \A ? \B : \A); endcode -code argQ ffC ffCcemux ffCrstmux ffCcepol ffCrstpol sigC clock - if (param(dsp, \CREG).as_int() == 0 && sigC != sigP) { - argQ = sigC; - subpattern(in_dffe); - if (dff) { - ffC = dff; - clock = dffclock; - if (dffrstmux) { - ffCrstmux = dffrstmux; - ffCrstpol = dffrstpol; - } - if (dffcemux) { - ffCcemux = dffcemux; - ffCcepol = dffcepol; - } - sigC = dffD; - } - } -endcode - match overflow if ffP if param(dsp, \USE_PATTERN_DETECT, Const("NO_PATDET")).decode_string() == "NO_PATDET" diff --git a/passes/pmgen/xilinx_dsp_CREG.pmg b/passes/pmgen/xilinx_dsp_CREG.pmg new file mode 100644 index 000000000..d79abdd4a --- /dev/null +++ b/passes/pmgen/xilinx_dsp_CREG.pmg @@ -0,0 +1,178 @@ +pattern xilinx_dsp_packC + +udata > unextend +state clock +state sigC sigP +state ffCcepol ffCrstpol +state ffC ffCcemux ffCrstmux + +// subpattern +state argQ argD +state ffcepol ffrstpol +state ffoffset +udata dffD dffQ +udata dffclock +udata dff dffcemux dffrstmux +udata dffcepol dffrstpol + +match dsp + select dsp->type.in(\DSP48E1) + select param(dsp, \CREG, 1).as_int() == 0 + select nusers(port(dsp, \C, SigSpec())) > 1 +endmatch + +code argQ ffC ffCcemux ffCrstmux ffCcepol ffCrstpol sigC sigP clock + unextend = [](const SigSpec &sig) { + int i; + for (i = GetSize(sig)-1; i > 0; i--) + if (sig[i] != sig[i-1]) + break; + // Do not remove non-const sign bit + if (sig[i].wire) + ++i; + return sig.extract(0, i); + }; + sigC = unextend(port(dsp, \C, SigSpec())); + + SigSpec P = port(dsp, \P); + if (param(dsp, \USE_MULT, Const("MULTIPLY")).decode_string() == "MULTIPLY") { + // Only care about those bits that are used + int i; + for (i = 0; i < GetSize(P); i++) { + if (nusers(P[i]) <= 1) + break; + sigP.append(P[i]); + } + log_assert(nusers(P.extract_end(i)) <= 1); + } + else + sigP = P; + + if (sigC == sigP) + reject; + + clock = port(dsp, \CLK, SigBit()); + + argQ = sigC; + subpattern(in_dffe); + if (dff) { + ffC = dff; + clock = dffclock; + if (dffrstmux) { + ffCrstmux = dffrstmux; + ffCrstpol = dffrstpol; + } + if (dffcemux) { + ffCcemux = dffcemux; + ffCcepol = dffcepol; + } + sigC = dffD; + } +endcode + +code + if (ffC) + accept; +endcode + +// ####################### + +subpattern in_dffe +arg argD argQ clock + +code + dff = nullptr; + for (auto c : argQ.chunks()) { + if (!c.wire) + reject; + if (c.wire->get_bool_attribute(\keep)) + reject; + } +endcode + +match ff + select ff->type.in($dff) + // DSP48E1 does not support clock inversion + select param(ff, \CLK_POLARITY).as_bool() + + slice offset GetSize(port(ff, \D)) + index port(ff, \Q)[offset] === argQ[0] + + // Check that the rest of argQ is present + filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ) + filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ + + set ffoffset offset +endmatch + +code argQ argD +{ + if (clock != SigBit() && port(ff, \CLK) != clock) + reject; + + SigSpec Q = port(ff, \Q); + dff = ff; + dffclock = port(ff, \CLK); + dffD = argQ; + argD = port(ff, \D); + argQ = Q; + dffD.replace(argQ, argD); + // Only search for ffrstmux if dffD only + // has two (ff, ffrstmux) users + if (nusers(dffD) > 2) + argD = SigSpec(); +} +endcode + +match ffrstmux + if !argD.empty() + select ffrstmux->type.in($mux) + index port(ffrstmux, \Y) === argD + + choice BA {\B, \A} + // DSP48E1 only supports reset to zero + select port(ffrstmux, BA).is_fully_zero() + + define pol (BA == \B) + set ffrstpol pol + semioptional +endmatch + +code argD + if (ffrstmux) { + dffrstmux = ffrstmux; + dffrstpol = ffrstpol; + argD = port(ffrstmux, ffrstpol ? \A : \B); + dffD.replace(port(ffrstmux, \Y), argD); + + // Only search for ffcemux if argQ has at + // least 3 users (ff, , ffrstmux) and + // dffD only has two (ff, ffrstmux) + if (!(nusers(argQ) >= 3 && nusers(dffD) == 2)) + argD = SigSpec(); + } + else + dffrstmux = nullptr; +endcode + +match ffcemux + if !argD.empty() + select ffcemux->type.in($mux) + index port(ffcemux, \Y) === argD + choice AB {\A, \B} + index port(ffcemux, AB) === argQ + define pol (AB == \A) + set ffcepol pol + semioptional +endmatch + +code argD + if (ffcemux) { + dffcemux = ffcemux; + dffcepol = ffcepol; + argD = port(ffcemux, ffcepol ? \B : \A); + dffD.replace(port(ffcemux, \Y), argD); + } + else + dffcemux = nullptr; +endcode -- cgit v1.2.3 From b824a56cde5aa692da2dc6b6a0d161a98daac6ef Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 23 Sep 2019 13:58:10 -0700 Subject: Comment to explain separating CREG packing --- passes/pmgen/xilinx_dsp.cc | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 86472feb5..a145ab184 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -606,6 +606,14 @@ struct XilinxDspPass : public Pass { xilinx_dsp_pm pm(module, module->selected_cells()); pm.run_xilinx_dsp_pack(xilinx_dsp_pack); } + // Separating out CREG packing is necessary since there + // is no guarantee that the cell ordering corresponds + // to the "expected" case (i.e. the order in which + // they appear in the source) thus the possiblity + // existed that a register got packed as CREG into a + // downstream DSP that should have otherwise been a + // PREG of an upstream DSP that had not been pattern + // matched yet { xilinx_dsp_CREG_pm pm(module, module->selected_cells()); pm.run_xilinx_dsp_packC(xilinx_dsp_packC); -- cgit v1.2.3 From e556d48d45b0795f5fb69333b55b9f7de90ff44d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 23 Sep 2019 16:00:11 -0700 Subject: Set [AB]CASCREG to legal values --- passes/pmgen/xilinx_dsp.cc | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index a145ab184..22df3e009 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -275,7 +275,6 @@ void xilinx_dsp_pack(xilinx_dsp_pm &pm) log_debug("postAddMux: %s\n", log_id(st.postAddMux, "--")); log_debug("ffP: %s %s %s\n", log_id(st.ffP, "--"), log_id(st.ffPcemux, "--"), log_id(st.ffPrstmux, "--")); log_debug("overflow: %s\n", log_id(st.overflow, "--")); - log_debug("\n"); Cell *cell = st.dsp; @@ -410,9 +409,12 @@ void xilinx_dsp_pack(xilinx_dsp_pm &pm) if (st.ffA1) { f(A, st.ffA1, st.ffA1cemux, st.ffA1cepol, ID(CEA1), st.ffA1rstmux, st.ffArstpol, IdString()); cell->setParam(ID(AREG), 2); + cell->setParam(ID(ACASCREG), 2); } - else + else { cell->setParam(ID(AREG), 1); + cell->setParam(ID(ACASCREG), 1); + } } if (st.ffB2) { SigSpec &B = cell->connections_.at(ID(B)); @@ -421,9 +423,12 @@ void xilinx_dsp_pack(xilinx_dsp_pm &pm) if (st.ffB1) { f(B, st.ffB1, st.ffB1cemux, st.ffB1cepol, ID(CEB1), st.ffB1rstmux, st.ffBrstpol, IdString()); cell->setParam(ID(BREG), 2); + cell->setParam(ID(BCASCREG), 2); } - else + else { cell->setParam(ID(BREG), 1); + cell->setParam(ID(BCASCREG), 1); + } } if (st.ffD) { SigSpec &D = cell->connections_.at(ID(D)); @@ -469,9 +474,8 @@ void xilinx_dsp_pack(xilinx_dsp_pm &pm) if (st.ffP) log(" ffP:%s", log_id(st.ffP)); - - log("\n"); } + log("\n"); SigSpec P = st.sigP; if (GetSize(P) < 48) @@ -624,7 +628,7 @@ struct XilinxDspPass : public Pass { xilinx_dsp_cascade_pm pm(module, module->selected_cells()); pm.run_xilinx_dsp_cascadeP(); //pm.run_xilinx_dsp_cascadeAB(); - break; + break; } while (did_something); } } -- cgit v1.2.3 From 44374b1b2b0dbc455c9e43d713e133d7d78a5e1a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 23 Sep 2019 21:58:40 -0700 Subject: "abc_padding" attr for blackbox outputs that were padded, remove them later --- passes/techmap/abc9.cc | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 7eac08d17..aa473e67d 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -606,7 +606,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri existing_cell = module->cell(c->name); log_assert(existing_cell); cell = module->addCell(remap_name(c->name), c->type); - module->swap_names(cell, existing_cell); } if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; @@ -642,8 +641,22 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri } } - for (auto cell : boxes) - module->remove(cell); + for (auto existing_cell : boxes) { + Cell *cell = module->cell(remap_name(existing_cell->name)); + if (cell) { + for (auto &conn : existing_cell->connections()) { + if (!conn.second.is_wire()) + continue; + Wire *wire = conn.second.as_wire(); + if (!wire->get_bool_attribute(ID(abc_padding))) + continue; + cell->unsetPort(conn.first); + log_debug("Dropping padded port connection for %s (%s) .%s (%s )\n", log_id(cell), cell->type.c_str(), log_id(conn.first), log_signal(conn.second)); + } + module->swap_names(cell, existing_cell); + } + module->remove(existing_cell); + } // Copy connections (and rename) from mapped_mod to module for (auto conn : mapped_mod->connections()) { -- cgit v1.2.3 From 6c427d36dd682b97da5f94cd7f0e261ad0802eef Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 24 Sep 2019 18:08:59 +0200 Subject: Add "portlist" command Signed-off-by: Clifford Wolf --- passes/cmds/Makefile.inc | 1 + passes/cmds/portlist.cc | 76 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 passes/cmds/portlist.cc (limited to 'passes') diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc index c8067a8be..cf9663d1d 100644 --- a/passes/cmds/Makefile.inc +++ b/passes/cmds/Makefile.inc @@ -25,6 +25,7 @@ OBJS += passes/cmds/plugin.o OBJS += passes/cmds/check.o OBJS += passes/cmds/qwp.o OBJS += passes/cmds/edgetypes.o +OBJS += passes/cmds/portlist.o OBJS += passes/cmds/chformal.o OBJS += passes/cmds/chtype.o OBJS += passes/cmds/blackbox.o diff --git a/passes/cmds/portlist.cc b/passes/cmds/portlist.cc new file mode 100644 index 000000000..6eedfbbf6 --- /dev/null +++ b/passes/cmds/portlist.cc @@ -0,0 +1,76 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * 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 PortlistPass : public Pass { + PortlistPass() : Pass("portlist", "list (top-level) ports") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" portlist [options] [selection]\n"); + log("\n"); + log("This command lists all module ports found in the selected modules.\n"); + log("\n"); + log("If no selection is provided then it lists the ports on the top module.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + // if (args[argidx] == "-ltr") { + // config.ltr = true; + // continue; + // } + break; + } + + auto handle_module = [&](RTLIL::Module *module) { + for (auto port : module->ports) { + auto *w = module->wire(port); + log("%s [%d:%d] %s\n", w->port_input ? w->port_output ? "inout" : "input" : "output", + w->upto ? w->start_offset : w->start_offset + w->width - 1, + w->upto ? w->start_offset + w->width - 1 : w->start_offset, + log_id(w)); + } + }; + + if (argidx == args.size()) + { + auto *top = design->top_module(); + if (top == nullptr) + log_error("Can't find top module in current design!\n"); + handle_module(top); + } + else + { + extra_args(args, argidx, design); + for (auto module : design->selected_modules()) + handle_module(module); + } + } +} PortlistPass; + +PRIVATE_NAMESPACE_END -- cgit v1.2.3 From b432c9b44b6d8033a835695b2a48cc3fe224bdec Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 25 Sep 2019 09:20:38 +0200 Subject: Improve "portlist" command Signed-off-by: Clifford Wolf --- passes/cmds/portlist.cc | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) (limited to 'passes') diff --git a/passes/cmds/portlist.cc b/passes/cmds/portlist.cc index 6eedfbbf6..38c4a8597 100644 --- a/passes/cmds/portlist.cc +++ b/passes/cmds/portlist.cc @@ -35,33 +35,50 @@ struct PortlistPass : public Pass { log("\n"); log("If no selection is provided then it lists the ports on the top module.\n"); log("\n"); + log(" -m\n"); + log(" print verilog blackbox module definitions instead of port lists\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { + bool m_mode = false; + size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - // if (args[argidx] == "-ltr") { - // config.ltr = true; - // continue; - // } + if (args[argidx] == "-m") { + m_mode = true; + continue; + } break; } + bool first_module = true; + auto handle_module = [&](RTLIL::Module *module) { + vector ports; + if (first_module) + first_module = false; + else + log("\n"); for (auto port : module->ports) { auto *w = module->wire(port); - log("%s [%d:%d] %s\n", w->port_input ? w->port_output ? "inout" : "input" : "output", - w->upto ? w->start_offset : w->start_offset + w->width - 1, - w->upto ? w->start_offset + w->width - 1 : w->start_offset, - log_id(w)); + ports.push_back(stringf("%s [%d:%d] %s", w->port_input ? w->port_output ? "inout" : "input" : "output", + w->upto ? w->start_offset : w->start_offset + w->width - 1, + w->upto ? w->start_offset + w->width - 1 : w->start_offset, + log_id(w))); } + log("module %s%s\n", log_id(module), m_mode ? " (" : ""); + for (int i = 0; i < GetSize(ports); i++) + log("%s%s\n", ports[i].c_str(), m_mode && i+1 < GetSize(ports) ? "," : ""); + if (m_mode) + log(");\nendmodule\n"); }; if (argidx == args.size()) { auto *top = design->top_module(); if (top == nullptr) - log_error("Can't find top module in current design!\n"); + log_cmd_error("Can't find top module in current design!\n"); handle_module(top); } else -- cgit v1.2.3 From 53ea5daa42db335a69d3fccbf237fe5555f4bccb Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 25 Sep 2019 14:04:36 -0700 Subject: Call 'wreduce' after mul2dsp to avoid unextend() --- passes/pmgen/xilinx_dsp.pmg | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 553195649..bca44c08d 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,6 +1,5 @@ pattern xilinx_dsp_pack -udata > unextend state clock state sigA sigB sigC sigD sigM sigP state postAddAB postAddMuxAB @@ -25,7 +24,7 @@ match dsp endmatch code sigA sigB sigC sigD sigM clock - unextend = [](const SigSpec &sig) { + auto unextend = [](const SigSpec &sig) { int i; for (i = GetSize(sig)-1; i > 0; i--) if (sig[i] != sig[i-1]) @@ -272,9 +271,9 @@ match postAdd filter !ffMcemux || nusers(port(postAdd, AB)) == 3 index port(postAdd, AB)[0] === sigP[0] - filter GetSize(unextend(port(postAdd, AB))) <= GetSize(sigP) - filter unextend(port(postAdd, AB)) == sigP.extract(0, GetSize(unextend(port(postAdd, AB)))) - filter nusers(sigP.extract_end(GetSize(unextend(port(postAdd, AB))))) <= 1 + filter GetSize(port(postAdd, AB)) <= GetSize(sigP) + filter port(postAdd, AB) == sigP.extract(0, GetSize(port(postAdd, AB))) + filter nusers(sigP.extract_end(GetSize(port(postAdd, AB)))) <= 1 set postAddAB AB optional endmatch -- cgit v1.2.3 From 486dd7c483d4277ffb09975fb943881bdc122f4d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 25 Sep 2019 14:05:59 -0700 Subject: unextend only used in init --- passes/pmgen/ice40_dsp.pmg | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 046aae9e2..9330dd09b 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -1,6 +1,5 @@ pattern ice40_dsp -udata > unextend state clock state clock_pol cd_signed o_lo state sigA sigB sigCD sigH sigO @@ -28,7 +27,7 @@ match mul endmatch code sigA sigB sigH - unextend = [](const SigSpec &sig) { + auto unextend = [](const SigSpec &sig) { int i; for (i = GetSize(sig)-1; i > 0; i--) if (sig[i] != sig[i-1]) -- cgit v1.2.3 From 5f8917c98491edd352dce96c63187aa814c32192 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 25 Sep 2019 16:45:51 -0700 Subject: Fix memory issue since SigSpec& could be invalidated --- passes/pmgen/xilinx_dsp.cc | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 22df3e009..db8fba38b 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -403,9 +403,8 @@ void xilinx_dsp_pack(xilinx_dsp_pm &pm) }; if (st.ffA2) { - SigSpec &A = cell->connections_.at(ID(A)); + SigSpec A = cell->getPort(ID(A)); f(A, st.ffA2, st.ffA2cemux, st.ffA2cepol, ID(CEA2), st.ffA2rstmux, st.ffArstpol, ID(RSTA)); - pm.add_siguser(A, cell); if (st.ffA1) { f(A, st.ffA1, st.ffA1cemux, st.ffA1cepol, ID(CEA1), st.ffA1rstmux, st.ffArstpol, IdString()); cell->setParam(ID(AREG), 2); @@ -415,11 +414,12 @@ void xilinx_dsp_pack(xilinx_dsp_pm &pm) cell->setParam(ID(AREG), 1); cell->setParam(ID(ACASCREG), 1); } + pm.add_siguser(A, cell); + cell->setPort(ID(A), A); } if (st.ffB2) { - SigSpec &B = cell->connections_.at(ID(B)); + SigSpec B = cell->getPort(ID(B)); f(B, st.ffB2, st.ffB2cemux, st.ffB2cepol, ID(CEB2), st.ffB2rstmux, st.ffBrstpol, ID(RSTB)); - pm.add_siguser(B, cell); if (st.ffB1) { f(B, st.ffB1, st.ffB1cemux, st.ffB1cepol, ID(CEB1), st.ffB1rstmux, st.ffBrstpol, IdString()); cell->setParam(ID(BREG), 2); @@ -429,11 +429,14 @@ void xilinx_dsp_pack(xilinx_dsp_pm &pm) cell->setParam(ID(BREG), 1); cell->setParam(ID(BCASCREG), 1); } + pm.add_siguser(B, cell); + cell->setPort(ID(B), B); } if (st.ffD) { - SigSpec &D = cell->connections_.at(ID(D)); + SigSpec D = cell->getPort(ID(D)); f(D, st.ffD, st.ffDcemux, st.ffDcepol, ID(CED), st.ffDrstmux, st.ffDrstpol, ID(RSTD)); pm.add_siguser(D, cell); + cell->setPort(ID(D), D); cell->setParam(ID(DREG), 1); } if (st.ffM) { @@ -539,9 +542,10 @@ void xilinx_dsp_packC(xilinx_dsp_CREG_pm &pm) }; if (st.ffC) { - SigSpec &C = cell->connections_.at(ID(C)); + SigSpec C = cell->getPort(ID(C)); f(C, st.ffC, st.ffCcemux, st.ffCcepol, ID(CEC), st.ffCrstmux, st.ffCrstpol, ID(RSTC)); pm.add_siguser(C, cell); + cell->setPort(ID(C), C); cell->setParam(ID(CREG), 1); } -- cgit v1.2.3 From aeb15398182abf5de7e340976e204195ab80a739 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 25 Sep 2019 17:22:30 -0700 Subject: Rework xilinx_dsp postAdd for new wreduce call --- passes/pmgen/xilinx_dsp.pmg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index bca44c08d..e256f7d7e 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -271,9 +271,9 @@ match postAdd filter !ffMcemux || nusers(port(postAdd, AB)) == 3 index port(postAdd, AB)[0] === sigP[0] - filter GetSize(port(postAdd, AB)) <= GetSize(sigP) - filter port(postAdd, AB) == sigP.extract(0, GetSize(port(postAdd, AB))) - filter nusers(sigP.extract_end(GetSize(port(postAdd, AB)))) <= 1 + filter GetSize(port(postAdd, AB)) >= GetSize(sigP) + filter port(postAdd, AB).extract(0, GetSize(sigP)) == sigP + filter port(postAdd, AB).extract_end(GetSize(sigP)) == SigSpec(sigP[GetSize(sigP)-1], GetSize(port(postAdd, AB))-GetSize(sigP)) set postAddAB AB optional endmatch -- cgit v1.2.3 From cd8a640989d0819266d2678304951de2a247405d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 25 Sep 2019 18:21:08 -0700 Subject: Reject if (* init *) present --- passes/pmgen/ice40_dsp.pmg | 3 +++ passes/pmgen/xilinx_dsp.pmg | 3 +++ 2 files changed, 6 insertions(+) (limited to 'passes') diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 9330dd09b..6b6d2b56f 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -333,6 +333,9 @@ code reject; if (c.wire->get_bool_attribute(\keep)) reject; + Const init = c.wire->attributes.at(\init, State::Sx); + if (!init.is_fully_undef() && !init.is_fully_zero()) + reject; } endcode diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index e256f7d7e..0a345e88d 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -355,6 +355,9 @@ code reject; if (c.wire->get_bool_attribute(\keep)) reject; + Const init = c.wire->attributes.at(\init, State::Sx); + if (!init.is_fully_undef() && !init.is_fully_zero()) + reject; } endcode -- cgit v1.2.3 From f1de93edf5b5c73440d445d8d6fa32251d2bdab1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 25 Sep 2019 22:58:03 -0700 Subject: Do not die if DSP48E1.P has no users (would otherwise get 'clean'-ed) --- passes/pmgen/xilinx_dsp.pmg | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 0a345e88d..3d0b1f2c3 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -53,6 +53,10 @@ code sigA sigB sigC sigD sigM clock } else sigM = P; + // This sigM could have no users if downstream $add + // is narrower than $mul result, for example + if (sigM.empty()) + reject; clock = port(dsp, \CLK, SigBit()); endcode @@ -261,7 +265,7 @@ endcode match postAdd // Ensure that Z mux is not already used - if port(dsp, \OPMODE).extract(4,3).is_fully_zero() + if port(dsp, \OPMODE, SigSpec()).extract(4,3).is_fully_zero() select postAdd->type.in($add) select GetSize(port(postAdd, \Y)) <= 48 -- cgit v1.2.3 From c0bb1d22e81b935e90032ed886e58787b3e61df5 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 26 Sep 2019 10:31:55 -0700 Subject: Remove newline --- passes/pmgen/xilinx_dsp.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index db8fba38b..4c297a50a 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -494,7 +494,6 @@ void xilinx_dsp_packC(xilinx_dsp_CREG_pm &pm) log_debug("Analysing %s.%s for Xilinx DSP packing (CREG).\n", log_id(pm.module), log_id(st.dsp)); log_debug("ffC: %s %s %s\n", log_id(st.ffC, "--"), log_id(st.ffCcemux, "--"), log_id(st.ffCrstmux, "--")); - log_debug("\n"); Cell *cell = st.dsp; -- cgit v1.2.3 From bd8661e0247121cf411b4c35fcedbc12a5919b50 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 26 Sep 2019 10:32:01 -0700 Subject: CREG to check for \keep --- passes/pmgen/xilinx_dsp_CREG.pmg | 3 +++ 1 file changed, 3 insertions(+) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp_CREG.pmg b/passes/pmgen/xilinx_dsp_CREG.pmg index d79abdd4a..a31dc80bf 100644 --- a/passes/pmgen/xilinx_dsp_CREG.pmg +++ b/passes/pmgen/xilinx_dsp_CREG.pmg @@ -87,6 +87,9 @@ code reject; if (c.wire->get_bool_attribute(\keep)) reject; + Const init = c.wire->attributes.at(\init, State::Sx); + if (!init.is_fully_undef() && !init.is_fully_zero()) + reject; } endcode -- cgit v1.2.3 From 832216dab072cb4f1793aeda07604fb2eb32b399 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 26 Sep 2019 12:09:57 -0700 Subject: Try recursive pmgen for P cascade --- passes/pmgen/xilinx_dsp_cascade.pmg | 206 +++++++++++++++++++++--------------- 1 file changed, 118 insertions(+), 88 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp_cascade.pmg b/passes/pmgen/xilinx_dsp_cascade.pmg index 37674efea..59cd1267d 100644 --- a/passes/pmgen/xilinx_dsp_cascade.pmg +++ b/passes/pmgen/xilinx_dsp_cascade.pmg @@ -1,100 +1,133 @@ pattern xilinx_dsp_cascadeP -udata > unextend -state sigC - -match dsp_pcin - select dsp_pcin->type.in(\DSP48E1) - select !param(dsp_pcin, \CREG, State::S1).as_bool() - select port(dsp_pcin, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("011") - select nusers(port(dsp_pcin, \C, SigSpec())) > 1 - select nusers(port(dsp_pcin, \PCIN, SigSpec())) == 0 +udata >> chain longest_chain + +code +#define MAX_DSP_CASCADE 20 +endcode + +match first + select first->type.in(\DSP48E1) + select port(first, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("000") + select nusers(port(first, \PCOUT, SigSpec())) <= 1 endmatch -code sigC - unextend = [](const SigSpec &sig) { - int i; - for (i = GetSize(sig)-1; i > 0; i--) - if (sig[i] != sig[i-1]) - break; - // Do not remove non-const sign bit - if (sig[i].wire) - ++i; - return sig.extract(0, i); - }; - sigC = unextend(port(dsp_pcin, \C)); +code + longest_chain.clear(); + chain.emplace_back(first, false); + subpattern(tail); +finally + chain.pop_back(); + log_assert(chain.empty()); + if (GetSize(longest_chain) > 1) { + Cell *dsp = longest_chain.front().first; + + for (int i = 1; i < GetSize(longest_chain); i++) { + Cell *dsp_pcin = longest_chain[i].first; + bool shift17 = longest_chain[i].second; + + dsp_pcin->setPort(ID(C), Const(0, 48)); + + if (i % MAX_DSP_CASCADE > 0) { + Wire *cascade = module->addWire(NEW_ID, 48); + dsp_pcin->setPort(ID(PCIN), cascade); + dsp->setPort(ID(PCOUT), cascade); + add_siguser(cascade, dsp_pcin); + add_siguser(cascade, dsp); + + SigSpec opmode = port(dsp_pcin, \OPMODE, Const(0, 7)); + if (shift17) + opmode[6] = State::S1; + else + opmode[6] = State::S0; + + opmode[5] = State::S0; + opmode[4] = State::S1; + dsp_pcin->setPort(\OPMODE, opmode); + + log_debug("PCOUT -> PCIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin)); + } + else { + log_debug("Blocking PCOUT -> PCIN cascade for %s -> %s (exceeds max: %d)\n", log_id(dsp), log_id(dsp_pcin), MAX_DSP_CASCADE); + } + + dsp = dsp_pcin; + } + + did_something = true; + accept; + } endcode -match dsp_pcout - select dsp_pcout->type.in(\DSP48E1) - select nusers(port(dsp_pcout, \P, SigSpec())) > 1 - select nusers(port(dsp_pcout, \PCOUT, SigSpec())) <= 1 +// ------------------------------------------------------------------ - index port(dsp_pcout, \P)[0] === sigC[0] - filter GetSize(port(dsp_pcin, \P)) >= GetSize(sigC) - filter port(dsp_pcout, \P).extract(0, GetSize(sigC)) == sigC +subpattern tail +arg first - optional +match next + select next->type.in(\DSP48E1) + select !param(next, \CREG, State::S1).as_bool() + select port(next, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("011") + select nusers(port(next, \C, SigSpec())) > 1 + select nusers(port(next, \PCIN, SigSpec())) == 0 + index port(next, \C)[0] === port(chain.back().first, \P)[0] + semioptional endmatch -match dsp_pcout_shift17 - if !dsp_pcout - select dsp_pcout_shift17->type.in(\DSP48E1) - select nusers(port(dsp_pcout_shift17, \P, SigSpec())) > 1 - select nusers(port(dsp_pcout_shift17, \PCOUT, SigSpec())) <= 1 - - index port(dsp_pcout_shift17, \P)[17] === sigC[0] - filter GetSize(port(dsp_pcout_shift17, \P)) >= GetSize(sigC)+17 - filter port(dsp_pcout_shift17, \P).extract(17, GetSize(sigC)) == sigC +match next_shift17 + if !next_shift17 + select next_shift17->type.in(\DSP48E1) + select !param(next_shift17, \CREG, State::S1).as_bool() + select port(next_shift17, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("011") + select nusers(port(next_shift17, \C, SigSpec())) > 1 + select nusers(port(next_shift17, \PCIN, SigSpec())) == 0 + index port(next_shift17, \C)[0] === port(chain.back().first, \P)[17] + semioptional endmatch -code - Cell *dsp; - if (dsp_pcout) - dsp = dsp_pcout; - else if (dsp_pcout_shift17) - dsp = dsp_pcout_shift17; - else log_abort(); - - dsp_pcin->setPort(ID(C), Const(0, 48)); - - Wire *cascade = module->addWire(NEW_ID, 48); - dsp_pcin->setPort(ID(PCIN), cascade); - dsp->setPort(ID(PCOUT), cascade); - add_siguser(cascade, dsp_pcin); - add_siguser(cascade, dsp); - - SigSpec opmode = port(dsp_pcin, \OPMODE, Const(0, 7)); - if (dsp_pcout) - opmode[6] = State::S0; - else if (dsp_pcout_shift17) - opmode[6] = State::S1; - else log_abort(); - - opmode[5] = State::S0; - opmode[4] = State::S1; - dsp_pcin->setPort(\OPMODE, opmode); - - log_debug("PCOUT -> PCIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin)); - - if (nusers(port(dsp_pcin, \PCOUT, SigSpec())) > 1) { - log_debug(" Saturated PCIN/PCOUT on %s\n", log_id(dsp_pcin)); - blacklist(dsp_pcin); - } - if (nusers(port(dsp, \PCIN, SigSpec())) > 1) { - log_debug(" Saturated PCIN/PCOUT on %s\n", log_id(dsp)); - blacklist(dsp_pcout); - } +code next + if (!next) + next = next_shift17; + if (next) { + chain.emplace_back(next, next_shift17); + + auto unextend = [](const SigSpec &sig) { + int i; + for (i = GetSize(sig)-1; i > 0; i--) + if (sig[i] != sig[i-1]) + break; + // Do not remove non-const sign bit + if (sig[i].wire) + ++i; + return sig.extract(0, i); + }; + SigSpec sigC = unextend(port(next, \C)); + + // TODO: Cannot use 'reject' since semioptional + if (next_shift17) { + if (GetSize(sigC)+17 <= GetSize(port(chain.back().first, \P)) && + port(chain.back().first, \P).extract(17, GetSize(sigC)) != sigC) + subpattern(tail); + } + else { + if (GetSize(sigC) <= GetSize(port(chain.back().first, \P)) && + port(chain.back().first, \P).extract(0, GetSize(sigC)) != sigC) + subpattern(tail); - did_something = true; - accept; + } + } else { + if (GetSize(chain) > GetSize(longest_chain)) + longest_chain = chain; + } +finally + if (next) + chain.pop_back(); endcode // ########## pattern xilinx_dsp_cascadeAB -udata > unextend state clock state sigA sigB @@ -113,8 +146,13 @@ udata dffclock udata dff dffcemux dffrstmux udata dffcepol dffrstpol -code - unextend = [](const SigSpec &sig) { +match dspD + select dspD->type.in(\DSP48E1) + select (param(dspD, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && nusers(port(dspD, \A, SigSpec())) > 1 && nusers(port(dspD, \ACIN, SigSpec())) == 0) || (param(dspD, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && nusers(port(dspD, \B, SigSpec())) > 1 && nusers(port(dspD, \BCIN, SigSpec())) == 0) +endmatch + +code sigA sigB + auto unextend = [](const SigSpec &sig) { int i; for (i = GetSize(sig)-1; i > 0; i--) if (sig[i] != sig[i-1]) @@ -124,14 +162,6 @@ code ++i; return sig.extract(0, i); }; -endcode - -match dspD - select dspD->type.in(\DSP48E1) - select (param(dspD, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && nusers(port(dspD, \A, SigSpec())) > 1 && nusers(port(dspD, \ACIN, SigSpec())) == 0) || (param(dspD, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && nusers(port(dspD, \B, SigSpec())) > 1 && nusers(port(dspD, \BCIN, SigSpec())) == 0) -endmatch - -code sigA sigB if (param(dspD, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT") sigA = unextend(port(dspD, \A)); if (param(dspD, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT") -- cgit v1.2.3 From af59856ba1be1f7cde3154994334f45500af6c22 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 26 Sep 2019 13:29:18 -0700 Subject: xilinx_dsp_cascade to also cascade AREG and BREG --- passes/pmgen/xilinx_dsp.cc | 42 ++- passes/pmgen/xilinx_dsp_cascade.pmg | 584 ++++++++++-------------------------- 2 files changed, 172 insertions(+), 454 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 4c297a50a..b0251de50 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -609,30 +609,26 @@ struct XilinxDspPass : public Pass { for (auto module : design->selected_modules()) { xilinx_simd_pack(module, module->selected_cells()); - { - xilinx_dsp_pm pm(module, module->selected_cells()); - pm.run_xilinx_dsp_pack(xilinx_dsp_pack); - } - // Separating out CREG packing is necessary since there - // is no guarantee that the cell ordering corresponds - // to the "expected" case (i.e. the order in which - // they appear in the source) thus the possiblity - // existed that a register got packed as CREG into a - // downstream DSP that should have otherwise been a - // PREG of an upstream DSP that had not been pattern - // matched yet - { - xilinx_dsp_CREG_pm pm(module, module->selected_cells()); - pm.run_xilinx_dsp_packC(xilinx_dsp_packC); - } - - do { - did_something = false; + { + xilinx_dsp_pm pm(module, module->selected_cells()); + pm.run_xilinx_dsp_pack(xilinx_dsp_pack); + } + // Separating out CREG packing is necessary since there + // is no guarantee that the cell ordering corresponds + // to the "expected" case (i.e. the order in which + // they appear in the source) thus the possiblity + // existed that a register got packed as CREG into a + // downstream DSP that should have otherwise been a + // PREG of an upstream DSP that had not been pattern + // matched yet + { + xilinx_dsp_CREG_pm pm(module, module->selected_cells()); + pm.run_xilinx_dsp_packC(xilinx_dsp_packC); + } + { xilinx_dsp_cascade_pm pm(module, module->selected_cells()); - pm.run_xilinx_dsp_cascadeP(); - //pm.run_xilinx_dsp_cascadeAB(); - break; - } while (did_something); + pm.run_xilinx_dsp_cascade(); + } } } } XilinxDspPass; diff --git a/passes/pmgen/xilinx_dsp_cascade.pmg b/passes/pmgen/xilinx_dsp_cascade.pmg index 59cd1267d..2fc943a66 100644 --- a/passes/pmgen/xilinx_dsp_cascade.pmg +++ b/passes/pmgen/xilinx_dsp_cascade.pmg @@ -1,6 +1,19 @@ -pattern xilinx_dsp_cascadeP +pattern xilinx_dsp_cascade -udata >> chain longest_chain +udata > unextend +udata >> chain longest_chain +state next +state clock +state AREG BREG + +// subpattern +state argQ argD +state ffcepol ffrstpol +state ffoffset +udata dffD dffQ +udata dffclock +udata dff dffcemux dffrstmux +udata dffcepol dffrstpol code #define MAX_DSP_CASCADE 20 @@ -14,41 +27,71 @@ endmatch code longest_chain.clear(); - chain.emplace_back(first, false); + chain.emplace_back(first, -1, -1, -1); subpattern(tail); finally chain.pop_back(); log_assert(chain.empty()); if (GetSize(longest_chain) > 1) { - Cell *dsp = longest_chain.front().first; + Cell *dsp = std::get<0>(longest_chain.front()); + Cell *dsp_pcin; + int P, AREG, BREG; for (int i = 1; i < GetSize(longest_chain); i++) { - Cell *dsp_pcin = longest_chain[i].first; - bool shift17 = longest_chain[i].second; + std::tie(dsp_pcin,P,AREG,BREG) = longest_chain[i]; dsp_pcin->setPort(ID(C), Const(0, 48)); if (i % MAX_DSP_CASCADE > 0) { - Wire *cascade = module->addWire(NEW_ID, 48); - dsp_pcin->setPort(ID(PCIN), cascade); - dsp->setPort(ID(PCOUT), cascade); - add_siguser(cascade, dsp_pcin); - add_siguser(cascade, dsp); - - SigSpec opmode = port(dsp_pcin, \OPMODE, Const(0, 7)); - if (shift17) - opmode[6] = State::S1; - else - opmode[6] = State::S0; - - opmode[5] = State::S0; - opmode[4] = State::S1; - dsp_pcin->setPort(\OPMODE, opmode); - - log_debug("PCOUT -> PCIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin)); + if (P >= 0) { + Wire *cascade = module->addWire(NEW_ID, 48); + dsp_pcin->setPort(ID(PCIN), cascade); + dsp->setPort(ID(PCOUT), cascade); + add_siguser(cascade, dsp_pcin); + add_siguser(cascade, dsp); + + SigSpec opmode = port(dsp_pcin, \OPMODE, Const(0, 7)); + if (P == 17) + opmode[6] = State::S1; + else if (P == 0) + opmode[6] = State::S0; + else log_abort(); + + opmode[5] = State::S0; + opmode[4] = State::S1; + dsp_pcin->setPort(\OPMODE, opmode); + + log_debug("PCOUT -> PCIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin)); + } + if (AREG >= 0) { + Wire *cascade = module->addWire(NEW_ID, 30); + dsp_pcin->setPort(ID(ACIN), cascade); + dsp->setPort(ID(ACOUT), cascade); + dsp_pcin->unsetPort(ID(A)); + add_siguser(cascade, dsp_pcin); + add_siguser(cascade, dsp); + + dsp->setParam(ID(ACASCREG), AREG); + dsp_pcin->setParam(ID(A_INPUT), Const("CASCADE")); + + log_debug("ACOUT -> ACIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin)); + } + if (BREG >= 0) { + Wire *cascade = module->addWire(NEW_ID, 18); + dsp_pcin->setPort(ID(BCIN), cascade); + dsp->setPort(ID(BCOUT), cascade); + dsp_pcin->unsetPort(ID(B)); + add_siguser(cascade, dsp_pcin); + add_siguser(cascade, dsp); + + dsp->setParam(ID(BCASCREG), BREG); + dsp_pcin->setParam(ID(B_INPUT), Const("CASCADE")); + + log_debug("BCOUT -> BCIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin)); + } } else { - log_debug("Blocking PCOUT -> PCIN cascade for %s -> %s (exceeds max: %d)\n", log_id(dsp), log_id(dsp_pcin), MAX_DSP_CASCADE); + log_debug(" Blocking %s -> %s cascade (exceeds max: %d)\n", log_id(dsp), log_id(dsp_pcin), MAX_DSP_CASCADE); } dsp = dsp_pcin; @@ -63,35 +106,35 @@ endcode subpattern tail arg first - -match next - select next->type.in(\DSP48E1) - select !param(next, \CREG, State::S1).as_bool() - select port(next, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("011") - select nusers(port(next, \C, SigSpec())) > 1 - select nusers(port(next, \PCIN, SigSpec())) == 0 - index port(next, \C)[0] === port(chain.back().first, \P)[0] +arg next + +match nextP + select nextP->type.in(\DSP48E1) + select !param(nextP, \CREG, State::S1).as_bool() + select port(nextP, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("011") + select nusers(port(nextP, \C, SigSpec())) > 1 + select nusers(port(nextP, \PCIN, SigSpec())) == 0 + index port(nextP, \C)[0] === port(std::get<0>(chain.back()), \P)[0] semioptional endmatch -match next_shift17 - if !next_shift17 - select next_shift17->type.in(\DSP48E1) - select !param(next_shift17, \CREG, State::S1).as_bool() - select port(next_shift17, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("011") - select nusers(port(next_shift17, \C, SigSpec())) > 1 - select nusers(port(next_shift17, \PCIN, SigSpec())) == 0 - index port(next_shift17, \C)[0] === port(chain.back().first, \P)[17] +match nextP_shift17 + if !nextP + select nextP_shift17->type.in(\DSP48E1) + select !param(nextP_shift17, \CREG, State::S1).as_bool() + select port(nextP_shift17, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("011") + select nusers(port(nextP_shift17, \C, SigSpec())) > 1 + select nusers(port(nextP_shift17, \PCIN, SigSpec())) == 0 + index port(nextP_shift17, \C)[0] === port(std::get<0>(chain.back()), \P)[17] semioptional endmatch code next - if (!next) - next = next_shift17; + next = nextP; + if (!nextP) + next = nextP_shift17; if (next) { - chain.emplace_back(next, next_shift17); - - auto unextend = [](const SigSpec &sig) { + unextend = [](const SigSpec &sig) { int i; for (i = GetSize(sig)-1; i > 0; i--) if (sig[i] != sig[i-1]) @@ -101,418 +144,94 @@ code next ++i; return sig.extract(0, i); }; - SigSpec sigC = unextend(port(next, \C)); - - // TODO: Cannot use 'reject' since semioptional - if (next_shift17) { - if (GetSize(sigC)+17 <= GetSize(port(chain.back().first, \P)) && - port(chain.back().first, \P).extract(17, GetSize(sigC)) != sigC) - subpattern(tail); - } - else { - if (GetSize(sigC) <= GetSize(port(chain.back().first, \P)) && - port(chain.back().first, \P).extract(0, GetSize(sigC)) != sigC) - subpattern(tail); - - } - } else { - if (GetSize(chain) > GetSize(longest_chain)) - longest_chain = chain; } -finally - if (next) - chain.pop_back(); -endcode - -// ########## - -pattern xilinx_dsp_cascadeAB - -state clock -state sigA sigB - -state ffA1cepol ffA2cepol ffB1cepol ffB2cepol -state ffArstpol ffBrstpol - -state ffA1 ffA1cemux ffA1rstmux ffA2 ffA2cemux ffA2rstmux -state ffB1 ffB1cemux ffB1rstmux ffB2 ffB2cemux ffB2rstmux - -// subpattern -state argQ argD -state ffcepol ffrstpol -state ffoffset -udata dffD dffQ -udata dffclock -udata dff dffcemux dffrstmux -udata dffcepol dffrstpol - -match dspD - select dspD->type.in(\DSP48E1) - select (param(dspD, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && nusers(port(dspD, \A, SigSpec())) > 1 && nusers(port(dspD, \ACIN, SigSpec())) == 0) || (param(dspD, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && nusers(port(dspD, \B, SigSpec())) > 1 && nusers(port(dspD, \BCIN, SigSpec())) == 0) -endmatch - -code sigA sigB - auto unextend = [](const SigSpec &sig) { - int i; - for (i = GetSize(sig)-1; i > 0; i--) - if (sig[i] != sig[i-1]) - break; - // Do not remove non-const sign bit - if (sig[i].wire) - ++i; - return sig.extract(0, i); - }; - if (param(dspD, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT") - sigA = unextend(port(dspD, \A)); - if (param(dspD, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT") - sigB = unextend(port(dspD, \B)); endcode -code argQ ffA2 ffA2cemux ffA2rstmux ffA2cepol ffArstpol ffA1 ffA1cemux ffA1rstmux ffA1cepol sigA clock - if (!sigA.empty()) { - argQ = sigA; - subpattern(in_dffe); - if (dff) { - ffA2 = dff; - clock = dffclock; - if (dffrstmux) { - ffA2rstmux = dffrstmux; - ffArstpol = dffrstpol; - } - if (dffcemux) { - ffA2cemux = dffcemux; - ffA2cepol = dffcepol; - } - sigA = dffD; - - // Now attempt to match A1 - argQ = sigA; +code argQ clock AREG + AREG = 0; + if (next) { + Cell *prev = std::get<0>(chain.back()); + if (param(prev, \AREG, 2).as_int() > 0 && + param(next, \AREG, 2).as_int() > 0 && + param(next, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && + port(next, \ACIN, SigSpec()).is_fully_zero() && + nusers(port(prev, \ACOUT, SigSpec())) <= 1) { + argQ = unextend(port(next, \A)); + clock = port(prev, \CLK); subpattern(in_dffe); if (dff) { - if ((ffA2rstmux != nullptr) ^ (dffrstmux != nullptr)) - goto reject_ffA1; - if (dffrstmux) { - if (ffArstpol != dffrstpol) - goto reject_ffA1; - if (port(ffA2rstmux, \S) != port(dffrstmux, \S)) - goto reject_ffA1; - ffA1rstmux = dffrstmux; - } - - ffA1 = dff; - clock = dffclock; - - if (dffcemux) { - ffA1cemux = dffcemux; - ffA1cepol = dffcepol; - } - sigA = dffD; - -reject_ffA1: ; + if (!dffrstmux && port(prev, \RSTA, State::S0) != State::S0) + goto reject_AREG; + if (dffrstmux && port(dffrstmux, \S) != port(prev, \RSTA, State::S0)) + goto reject_AREG; + if (!dffcemux && port(prev, \CEA2, State::S0) != State::S0) + goto reject_AREG; + if (dffcemux && port(dffcemux, \S) != port(prev, \CEA2, State::S0)) + goto reject_AREG; + if (dffD == unextend(port(prev, \A))) + AREG = 1; +reject_AREG: ; } } } endcode -match dspQA2 - if ffA1 - select dspQA2->type.in(\DSP48E1) - select param(dspQA2, \A_REG, 2).as_int() == 2 - select nusers(port(dspQA2, \A, SigSpec())) > 1 - select nusers(port(dspQA2, \ACOUT, SigSpec())) == 0 - slice offset GetSize(port(dspQA2, \A)) - index port(dspQA2, \A)[offset] === sigA[0] - index port(dspQA2, \CLK, State::S0) === port(dspD, \CLK, State::S0) - - // Check that the rest of sigA is present - filter GetSize(port(dspQA2, \A)) >= offset + GetSize(sigA) - filter port(dspQA2, \A).extract(offset, GetSize(sigA)) == sigA - - optional -endmatch - -code - if (dspQA2) { - // Check CE and RST are compatible - if ((ffA1cemux != nullptr) == port(dspQA2, \CEA1, State::S1).is_fully_const()) - reject; - if ((ffA2cemux != nullptr) == port(dspQA2, \CEA2, State::S1).is_fully_const()) - reject; - if ((ffA1rstmux != nullptr) == port(dspQA2, \RSTA, State::S0).is_fully_const()) - reject; - if ((ffA2rstmux != nullptr) == port(dspQA2, \RSTA, State::S0).is_fully_const()) - reject; - - if (ffA1cemux) { - if (port(dspQA2, \CEA1) != port(ffA1cemux, \S)) - reject; - // TODO: Support inversions - if (!ffA1cepol) - reject; - } - if (ffA2cemux) { - if (port(dspQA2, \CEA2) != port(ffA2cemux, \S)) - reject; - // TODO: Support inversions - if (!ffA2cepol) - reject; - } - if (ffA1rstmux) { - if (port(dspQA2, \RSTA) != port(ffA1rstmux, \S)) - reject; - // TODO: Support inversions - if (!ffArstpol) - reject; - } - if (ffA2rstmux) { - if (port(dspQA2, \RSTA) != port(ffA2rstmux, \S)) - reject; - // TODO: Support inversions - if (!ffArstpol) - reject; - } - } -endcode - -match dspQA1 - if !dspQA1 && !ffA1 - if ffA2 - select dspQA1->type.in(\DSP48E1) - select param(dspQA1, \A_REG, 2).as_int() == 1 - select nusers(port(dspQA1, \A, SigSpec())) > 1 - select nusers(port(dspQA1, \ACOUT, SigSpec())) == 0 - slice offset GetSize(port(dspQA1, \A)) - index port(dspQA1, \A)[offset] === sigA[0] - index port(dspQA1, \CLK, State::S0) === port(dspD, \CLK, State::S0) - - // Check that the rest of sigA is present - filter GetSize(port(dspQA1, \A)) >= offset + GetSize(sigA) - filter port(dspQA1, \A).extract(offset, GetSize(sigA)) == sigA - - optional -endmatch - -code - if (dspQA1) { - // Check CE and RST are compatible - if ((ffA2cemux != NULL) == port(dspQA1, \CEA2, State::S1).is_fully_const()) - reject; - if ((ffA2rstmux != NULL) == port(dspQA1, \RSTA, State::S0).is_fully_const()) - reject; - - if (!ffA2cepol || !ffArstpol) - reject; - - if (ffA2cemux) { - if (port(dspQA1, \CEA2) != port(ffA2cemux, \S)) - reject; - // TODO: Support inversions - if (!ffA2cepol) - reject; - } - if (ffA2rstmux) { - if (port(dspQA1, \RSTA) != port(ffA2rstmux, \S)) - reject; - // TODO: Support inversions - if (!ffArstpol) - reject; - } - } -endcode - -code argQ ffB2 ffB2cemux ffB2rstmux ffB2cepol ffBrstpol ffB1 ffB1cemux ffB1rstmux ffB1cepol sigB clock - if (!sigB.empty()) { - argQ = sigB; - subpattern(in_dffe); - if (dff) { - ffB2 = dff; - clock = dffclock; - if (dffrstmux) { - ffB2rstmux = dffrstmux; - ffBrstpol = dffrstpol; - } - if (dffcemux) { - ffB2cemux = dffcemux; - ffB2cepol = dffcepol; - } - sigB = dffD; - - // Now attempt to match B1 - argQ = sigB; +code argQ clock BREG + BREG = 0; + if (next) { + Cell *prev = std::get<0>(chain.back()); + if (param(prev, \BREG, 2).as_int() > 0 && + param(next, \BREG, 2).as_int() > 0 && + param(next, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && + port(next, \BCIN, SigSpec()).is_fully_zero() && + nusers(port(prev, \BCOUT, SigSpec())) <= 1) { + argQ = unextend(port(next, \B)); + clock = port(prev, \CLK); subpattern(in_dffe); if (dff) { - if ((ffB2rstmux != nullptr) ^ (dffrstmux != nullptr)) - goto reject_ffB1; - if (dffrstmux) { - if (ffBrstpol != dffrstpol) - goto reject_ffB1; - if (port(ffB2rstmux, \S) != port(dffrstmux, \S)) - goto reject_ffB1; - ffB1rstmux = dffrstmux; - } - - ffB1 = dff; - clock = dffclock; - - if (dffcemux) { - ffB1cemux = dffcemux; - ffB1cepol = dffcepol; - } - sigB = dffD; - -reject_ffB1: ; + if (!dffrstmux && port(prev, \RSTB, State::S0) != State::S0) + goto reject_BREG; + if (dffrstmux && port(dffrstmux, \S) != port(prev, \RSTB, State::S0)) + goto reject_BREG; + if (!dffcemux && port(prev, \CEB2, State::S0) != State::S0) + goto reject_BREG; + if (dffcemux && port(dffcemux, \S) != port(prev, \CEB2, State::S0)) + goto reject_BREG; + if (dffD == unextend(port(prev, \B))) + BREG = 1; +reject_BREG: ; } } } endcode -match dspQB2 - if ffB1 - select dspQB2->type.in(\DSP48E1) - select param(dspQB2, \B_REG, 2).as_int() == 2 - select nusers(port(dspQB2, \B, SigSpec())) > 1 - select nusers(port(dspQB2, \BCOUT, SigSpec())) == 0 - slice offset GetSize(port(dspQB2, \B)) - index port(dspQB2, \B)[offset] === sigB[0] - index port(dspQB2, \CLK, State::S0) === port(dspD, \CLK, State::S0) - - // Check that the rest of sigB is present - filter GetSize(port(dspQB2, \B)) >= offset + GetSize(sigB) - filter port(dspQB2, \B).extract(offset, GetSize(sigB)) == sigB - - optional -endmatch - code - if (dspQB2) { - // Check CE and RST are compatible - if ((ffB1cemux != nullptr) == port(dspQB2, \CEB1, State::S1).is_fully_const()) - reject; - if ((ffB2cemux != NULL) == port(dspQB2, \CEB2, State::S1).is_fully_const()) - reject; - if ((ffB1rstmux != NULL) == port(dspQB2, \RSTB, State::S0).is_fully_const()) - reject; - if ((ffB2rstmux != NULL) == port(dspQB2, \RSTB, State::S0).is_fully_const()) - reject; - - if (ffB1cemux) { - if (port(dspQB2, \CEB1) != port(ffB1cemux, \S)) - reject; - // TODO: Support inversions - if (!ffB1cepol) - reject; - } - if (ffB2cemux) { - if (port(dspQB2, \CEB2) != port(ffB2cemux, \S)) - reject; - // TODO: Support inversions - if (!ffB2cepol) - reject; - } - if (ffB2rstmux) { - if (port(dspQB2, \RSTB) != port(ffB2rstmux, \S)) - reject; - // TODO: Support inversions - if (!ffBrstpol) - reject; - } - } -endcode - -match dspQB1 - if !dspQB1 && !ffB1 - if ffB2 - select dspQB1->type.in(\DSP48E1) - select param(dspQB1, \B_REG, 2).as_int() >= 1 - select nusers(port(dspQB1, \B, SigSpec())) > 1 - select nusers(port(dspQB1, \BCOUT, SigSpec())) == 0 - slice offset GetSize(port(dspQB1, \B)) - index port(dspQB1, \B)[offset] === sigB[0] - index port(dspQB1, \CLK, State::S0) === port(dspD, \CLK, State::S0) - - // Check that the rest of sigB is present - filter GetSize(port(dspQB1, \B)) >= offset + GetSize(sigB) - filter port(dspQB1, \B).extract(offset, GetSize(sigB)) == sigB - - optional -endmatch - -code - if (dspQB1) { - // Check CE and RST are compatible - if ((ffB2cemux != NULL) != port(dspQB1, \CEB2, State::S1).is_fully_const()) - reject; - if ((ffB2rstmux != NULL) != port(dspQB1, \RSTB, State::S0).is_fully_const()) - reject; - - if (!ffA2cepol || !ffArstpol) - reject; + if (next) { + chain.emplace_back(next, nextP_shift17 ? 17 : nextP ? 0 : -1, AREG, BREG); - if (ffA2cemux) { - if (port(dspQB1, \CEB2) != port(ffB2cemux, \S)) - reject; - // TODO: Support inversions - if (!ffA2cepol) - reject; - } - if (ffA2rstmux) { - if (port(dspQB1, \RSTB) != port(ffB2rstmux, \S)) - reject; - // TODO: Support inversions - if (!ffArstpol) - reject; - } - } -endcode + SigSpec sigC = unextend(port(next, \C)); -code - if (dspQA1 || dspQA2) { - dspD->setParam(\A_INPUT, Const("CASCADE")); - dspD->setPort(\A, Const(0, 30)); - - Wire *cascade = module->addWire(NEW_ID, 30); - if (dspQA1) { - dspQA1->setParam(\ACASCREG, 1); - dspQA1->setPort(\ACOUT, cascade); - log_debug("ACOUT -> ACIN cascade for %s -> %s\n", log_id(dspQA1), log_id(dspD)); - } - else if (dspQA2) { - dspQA2->setParam(\ACASCREG, 2); - dspQA2->setPort(\ACOUT, cascade); - log_debug("ACOUT -> ACIN cascade for %s -> %s\n", log_id(dspQA2), log_id(dspD)); + // TODO: Cannot use 'reject' since semioptional + if (nextP_shift17) { + if (GetSize(sigC)+17 <= GetSize(port(std::get<0>(chain.back()), \P)) && + port(std::get<0>(chain.back()), \P).extract(17, GetSize(sigC)) != sigC) + subpattern(tail); } - else - log_abort(); + else { + if (GetSize(sigC) <= GetSize(port(std::get<0>(chain.back()), \P)) && + port(std::get<0>(chain.back()), \P).extract(0, GetSize(sigC)) != sigC) + subpattern(tail); - dspD->setPort(\ACIN, cascade); - did_something = true; - } - if (dspQB1 || dspQB2) { - dspD->setParam(\B_INPUT, Const("CASCADE")); - dspD->setPort(\B, Const(0, 18)); - - Wire *cascade = module->addWire(NEW_ID, 18); - if (dspQB1) { - dspQB1->setParam(\BCASCREG, 1); - dspQB1->setPort(\BCOUT, cascade); - log_debug("BCOUT -> BCIN cascade for %s -> %s\n", log_id(dspQB1), log_id(dspD)); } - else if (dspQB2) { - dspQB2->setParam(\BCASCREG, 2); - dspQB2->setPort(\BCOUT, cascade); - log_debug("BCOUT -> BCIN cascade for %s -> %s\n", log_id(dspQB2), log_id(dspD)); - } - else - log_abort(); - - dspD->setPort(\BCIN, cascade); - did_something = true; + } else { + if (GetSize(chain) > GetSize(longest_chain)) + longest_chain = chain; } - - accept; +finally + if (next) + chain.pop_back(); endcode - // ####################### subpattern in_dffe @@ -525,6 +244,9 @@ code reject; if (c.wire->get_bool_attribute(\keep)) reject; + Const init = c.wire->attributes.at(\init, State::Sx); + if (!init.is_fully_undef() && !init.is_fully_zero()) + reject; } endcode -- cgit v1.2.3 From 58f31096abbb0bc68c8339c88b7db410b8edcdba Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 26 Sep 2019 13:40:38 -0700 Subject: Zero out ports --- passes/pmgen/xilinx_dsp_cascade.pmg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp_cascade.pmg b/passes/pmgen/xilinx_dsp_cascade.pmg index 2fc943a66..d4b4b8e22 100644 --- a/passes/pmgen/xilinx_dsp_cascade.pmg +++ b/passes/pmgen/xilinx_dsp_cascade.pmg @@ -67,7 +67,7 @@ finally Wire *cascade = module->addWire(NEW_ID, 30); dsp_pcin->setPort(ID(ACIN), cascade); dsp->setPort(ID(ACOUT), cascade); - dsp_pcin->unsetPort(ID(A)); + dsp_pcin->setPort(ID(A), Const(0, 30)); add_siguser(cascade, dsp_pcin); add_siguser(cascade, dsp); @@ -80,7 +80,7 @@ finally Wire *cascade = module->addWire(NEW_ID, 18); dsp_pcin->setPort(ID(BCIN), cascade); dsp->setPort(ID(BCOUT), cascade); - dsp_pcin->unsetPort(ID(B)); + dsp_pcin->setPort(ID(B), Const(0, 18)); add_siguser(cascade, dsp_pcin); add_siguser(cascade, dsp); -- cgit v1.2.3 From 95f0dd57df5209f77df6771e381b87871ab9860a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 26 Sep 2019 13:44:41 -0700 Subject: Update doc --- passes/pmgen/xilinx_dsp.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index b0251de50..5ccc47ba8 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -578,7 +578,8 @@ struct XilinxDspPass : public Pass { log("Use of the dedicated 'PCOUT' -> 'PCIN' cascade path is detected for 'P' -> 'C'\n"); log("connections (optionally, where 'P' is right-shifted by 17-bits and used as an\n"); log("input to the post-adder -- a pattern common for summing partial products to\n"); - log("implement wide multipliers).\n"); + log("implement wide multipliers). Initial support also exists for similar cascading\n"); + log("for AREG and BREG using '[AB]OUT' -> '[AB]IN'.\n"); log("\n"); log("\n"); log("Experimental feature: addition/subtractions less than 12 or 24 bits with the\n"); -- cgit v1.2.3 From 5b9deef10df2ab958112f6ff55f27776e492f187 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 26 Sep 2019 13:59:05 -0700 Subject: Do not always zero out C (e.g. during cascade breaks) --- passes/pmgen/xilinx_dsp.cc | 2 -- passes/pmgen/xilinx_dsp_cascade.pmg | 8 +++----- 2 files changed, 3 insertions(+), 7 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 5ccc47ba8..6ce5f2e16 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -24,8 +24,6 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -bool did_something; - #include "passes/pmgen/xilinx_dsp_pm.h" #include "passes/pmgen/xilinx_dsp_CREG_pm.h" #include "passes/pmgen/xilinx_dsp_cascade_pm.h" diff --git a/passes/pmgen/xilinx_dsp_cascade.pmg b/passes/pmgen/xilinx_dsp_cascade.pmg index d4b4b8e22..714316808 100644 --- a/passes/pmgen/xilinx_dsp_cascade.pmg +++ b/passes/pmgen/xilinx_dsp_cascade.pmg @@ -40,11 +40,10 @@ finally for (int i = 1; i < GetSize(longest_chain); i++) { std::tie(dsp_pcin,P,AREG,BREG) = longest_chain[i]; - dsp_pcin->setPort(ID(C), Const(0, 48)); - if (i % MAX_DSP_CASCADE > 0) { if (P >= 0) { Wire *cascade = module->addWire(NEW_ID, 48); + dsp_pcin->setPort(ID(C), Const(0, 48)); dsp_pcin->setPort(ID(PCIN), cascade); dsp->setPort(ID(PCOUT), cascade); add_siguser(cascade, dsp_pcin); @@ -65,9 +64,9 @@ finally } if (AREG >= 0) { Wire *cascade = module->addWire(NEW_ID, 30); + dsp_pcin->setPort(ID(A), Const(0, 30)); dsp_pcin->setPort(ID(ACIN), cascade); dsp->setPort(ID(ACOUT), cascade); - dsp_pcin->setPort(ID(A), Const(0, 30)); add_siguser(cascade, dsp_pcin); add_siguser(cascade, dsp); @@ -78,9 +77,9 @@ finally } if (BREG >= 0) { Wire *cascade = module->addWire(NEW_ID, 18); + dsp_pcin->setPort(ID(B), Const(0, 18)); dsp_pcin->setPort(ID(BCIN), cascade); dsp->setPort(ID(BCOUT), cascade); - dsp_pcin->setPort(ID(B), Const(0, 18)); add_siguser(cascade, dsp_pcin); add_siguser(cascade, dsp); @@ -97,7 +96,6 @@ finally dsp = dsp_pcin; } - did_something = true; accept; } endcode -- cgit v1.2.3 From 26657037b8de3cf09bafb2bca3940515dad96222 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 26 Sep 2019 14:31:02 -0700 Subject: Update doc with max cascade chain of 20 --- passes/pmgen/xilinx_dsp.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 6ce5f2e16..11c7e5ea8 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -576,8 +576,10 @@ struct XilinxDspPass : public Pass { log("Use of the dedicated 'PCOUT' -> 'PCIN' cascade path is detected for 'P' -> 'C'\n"); log("connections (optionally, where 'P' is right-shifted by 17-bits and used as an\n"); log("input to the post-adder -- a pattern common for summing partial products to\n"); - log("implement wide multipliers). Initial support also exists for similar cascading\n"); - log("for AREG and BREG using '[AB]OUT' -> '[AB]IN'.\n"); + log("implement wide multipliers). Limited support also exists for similar cascading\n"); + log("for A and B using '[AB]COUT' -> '[AB]CIN'. Currently, cascade chains are limited\n"); + log("to a maximum length of 20 cells, corresponding to the smallest Xilinx 7 Series\n"); + log("device.\n"); log("\n"); log("\n"); log("Experimental feature: addition/subtractions less than 12 or 24 bits with the\n"); -- cgit v1.2.3 From fd0e3a2c43d96ba31beede9865d5000230029994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Fri, 27 Sep 2019 11:03:04 +0200 Subject: Fix _TECHMAP_REMOVEINIT_ handling. Previously, this wire was handled in the code that populated the "do or do not" techmap cache, resulting in init value removal being performed only for the first use of a given template. Fixes the problem identified in #1396. --- passes/techmap/techmap.cc | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'passes') diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 1d0362ad6..08a1af2d5 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -935,19 +935,6 @@ struct TechmapWorker for (auto &it2 : it.second) if (!it2.value.is_fully_const()) log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(it2.wire->name), log_signal(it2.value)); - if (it.first.substr(0, 20) == "_TECHMAP_REMOVEINIT_" && techmap_do_cache[tpl]) { - for (auto &it2 : it.second) { - auto val = it2.value.as_const(); - auto wirename = RTLIL::escape_id(it.first.substr(20, it.first.size() - 20 - 1)); - auto it = cell->connections().find(wirename); - if (it != cell->connections().end()) { - auto sig = sigmap(it->second); - for (int i = 0; i < sig.size(); i++) - if (val[i] == State::S1) - remove_init_bits.insert(sig[i]); - } - } - } techmap_wire_names.erase(it.first); } @@ -973,6 +960,23 @@ struct TechmapWorker mkdebug.off(); } + TechmapWires twd = techmap_find_special_wires(tpl); + for (auto &it : twd) { + if (it.first.substr(0, 20) == "_TECHMAP_REMOVEINIT_") { + for (auto &it2 : it.second) { + auto val = it2.value.as_const(); + auto wirename = RTLIL::escape_id(it.first.substr(20, it.first.size() - 20 - 1)); + auto it = cell->connections().find(wirename); + if (it != cell->connections().end()) { + auto sig = sigmap(it->second); + for (int i = 0; i < sig.size(); i++) + if (val[i] == State::S1) + remove_init_bits.insert(sig[i]); + } + } + } + } + if (extern_mode && !in_recursion) { std::string m_name = stringf("$extern:%s", log_id(tpl)); -- cgit v1.2.3 From aebbfffd71ab6a85f86ef44f40b1d46a7d6a60ee Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 27 Sep 2019 11:57:53 -0700 Subject: Ooops AREG and BREG to default to -1 --- passes/pmgen/xilinx_dsp_cascade.pmg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/xilinx_dsp_cascade.pmg b/passes/pmgen/xilinx_dsp_cascade.pmg index 714316808..6f4ac5849 100644 --- a/passes/pmgen/xilinx_dsp_cascade.pmg +++ b/passes/pmgen/xilinx_dsp_cascade.pmg @@ -146,7 +146,7 @@ code next endcode code argQ clock AREG - AREG = 0; + AREG = -1; if (next) { Cell *prev = std::get<0>(chain.back()); if (param(prev, \AREG, 2).as_int() > 0 && @@ -175,7 +175,7 @@ reject_AREG: ; endcode code argQ clock BREG - BREG = 0; + BREG = -1; if (next) { Cell *prev = std::get<0>(chain.back()); if (param(prev, \BREG, 2).as_int() > 0 && -- cgit v1.2.3 From a39505e329cc05dbd4ad624a1cf0f6caf664fd9a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 27 Sep 2019 12:59:10 -0700 Subject: equiv_opt to call async2sync when not -multiclock like SymbiYosys --- passes/equiv/equiv_opt.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'passes') diff --git a/passes/equiv/equiv_opt.cc b/passes/equiv/equiv_opt.cc index d4c7f7953..9fe3bbd57 100644 --- a/passes/equiv/equiv_opt.cc +++ b/passes/equiv/equiv_opt.cc @@ -156,6 +156,8 @@ struct EquivOptPass:public ScriptPass if (check_label("prove")) { if (multiclock || help_mode) run("clk2fflogic", "(only with -multiclock)"); + else + run("async2sync", "(only without -multiclock)"); run("equiv_make gold gate equiv"); if (help_mode) run("equiv_induct [-undef] equiv"); -- cgit v1.2.3 From 3f70c1fd26eb109c2c4d899cce55f24bbf04acc1 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sun, 29 Sep 2019 13:22:11 +0200 Subject: Open aig frontend as binary file --- passes/techmap/abc9.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 7eac08d17..7c764451f 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -471,7 +471,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret); buffer = stringf("%s/%s", tempdir_name.c_str(), "output.aig"); - ifs.open(buffer); + ifs.open(buffer, std::ifstream::binary); if (ifs.fail()) log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); -- cgit v1.2.3 From 10e57f3880da8bfa373a3859a713509a549701c9 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 30 Sep 2019 14:58:23 +0200 Subject: Fix $dlatch handling in async2sync Signed-off-by: Clifford Wolf --- passes/sat/async2sync.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'passes') diff --git a/passes/sat/async2sync.cc b/passes/sat/async2sync.cc index 24ae6e448..740248545 100644 --- a/passes/sat/async2sync.cc +++ b/passes/sat/async2sync.cc @@ -198,6 +198,7 @@ struct Async2syncPass : public Pass { module->addMux(NEW_ID, sig_d, new_q, sig_en, sig_q); } + cell->setPort("\\D", sig_q); cell->setPort("\\Q", new_q); cell->unsetPort("\\EN"); cell->unsetParam("\\EN_POLARITY"); -- cgit v1.2.3 From a274b7cc86d4f64541d3d2903b4eeed4616ab1d8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 30 Sep 2019 10:59:56 -0700 Subject: Update doc for equiv_opt --- passes/equiv/equiv_opt.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/equiv/equiv_opt.cc b/passes/equiv/equiv_opt.cc index 9fe3bbd57..4ab5b1a3e 100644 --- a/passes/equiv/equiv_opt.cc +++ b/passes/equiv/equiv_opt.cc @@ -32,7 +32,8 @@ struct EquivOptPass:public ScriptPass log("\n"); log(" equiv_opt [options] [command]\n"); log("\n"); - log("This command checks circuit equivalence before and after an optimization pass.\n"); + log("This command uses temporal induction to check circuit equivalence before and\n"); + log("after an optimization pass.\n"); log("\n"); log(" -run :\n"); log(" only run the commands between the labels (see below). an empty\n"); @@ -156,7 +157,7 @@ struct EquivOptPass:public ScriptPass if (check_label("prove")) { if (multiclock || help_mode) run("clk2fflogic", "(only with -multiclock)"); - else + if (!multiclock || help_mode) run("async2sync", "(only without -multiclock)"); run("equiv_make gold gate equiv"); if (help_mode) -- cgit v1.2.3