aboutsummaryrefslogtreecommitdiffstats
path: root/passes/pmgen/xilinx_srl.pmg
diff options
context:
space:
mode:
Diffstat (limited to 'passes/pmgen/xilinx_srl.pmg')
-rw-r--r--passes/pmgen/xilinx_srl.pmg211
1 files changed, 211 insertions, 0 deletions
diff --git a/passes/pmgen/xilinx_srl.pmg b/passes/pmgen/xilinx_srl.pmg
new file mode 100644
index 000000000..0cc551e92
--- /dev/null
+++ b/passes/pmgen/xilinx_srl.pmg
@@ -0,0 +1,211 @@
+pattern fixed
+
+udata <vector<Cell*>> chain longest_chain
+udata <pool<Cell*>> non_first_cells
+udata <int> minlen
+udata <dict<std::pair<IdString,IdString>,Const>> default_params
+
+code
+ non_first_cells.clear();
+ subpattern(setup);
+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()
+ filter !non_first_cells.count(first)
+//generate
+// SigSpec A = module->addWire(NEW_ID);
+// SigSpec B = module->addWire(NEW_ID);
+// SigSpec Y = module->addWire(NEW_ID);
+// switch (rng(3))
+// {
+// case 0:
+// module->addAndGate(NEW_ID, A, B, Y);
+// break;
+// case 1:
+// module->addOrGate(NEW_ID, A, B, Y);
+// break;
+// case 2:
+// module->addXorGate(NEW_ID, A, B, Y);
+// break;
+// }
+endmatch
+
+code
+ longest_chain.clear();
+ chain.push_back(first);
+ subpattern(tail);
+finally
+ chain.pop_back();
+ log_assert(chain.empty());
+ if (GetSize(longest_chain) >= minlen)
+ accept;
+endcode
+
+// ------------------------------------------------------------------
+
+subpattern setup
+
+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()
+endmatch
+
+code
+ if (first->type.in(\FDRE, \FDRE_1)) {
+ SigBit R = port(first, \R);
+ if (first->type == \FDRE) {
+ auto inverted = first->parameters.at(\IS_R_INVERTED, default_params.at(std::make_pair(first->type,\IS_R_INVERTED))).as_bool();
+ if (!inverted && R != State::S0)
+ reject;
+ if (inverted && R != State::S1)
+ reject;
+ }
+ else if (first->type == \FDRE_1) {
+ if (R == State::S0)
+ reject;
+ }
+ else log_abort();
+ }
+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 nusers(port(next, \Q)) == 2
+ index <IdString> next->type === first->type
+ index <SigBit> port(next, \Q) === port(first, \D)
+endmatch
+
+code
+ if (next->type.in(\FDRE, \FDRE_1)) {
+ for (auto p : { \R })
+ if (port(next, p) != port(first, p))
+ reject;
+
+ if (next->type == \FDRE) {
+ for (auto p : { \IS_C_INVERTED, \IS_D_INVERTED, \IS_R_INVERTED }) {
+ auto n = next->parameters.at(p, default_params.at(std::make_pair(next->type,p)));
+ auto f = first->parameters.at(p, default_params.at(std::make_pair(first->type,p)));
+ if (n != f)
+ reject;
+ }
+ }
+ }
+ non_first_cells.insert(next);
+endcode
+
+// ------------------------------------------------------------------
+
+subpattern tail
+arg first
+
+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 nusers(port(next, \Q)) == 2
+ index <IdString> next->type === chain.back()->type
+ index <SigBit> port(next, \Q) === port(chain.back(), \D)
+//generate 10
+// SigSpec A = module->addWire(NEW_ID);
+// SigSpec B = module->addWire(NEW_ID);
+// SigSpec Y = port(chain.back().first, chain.back().second);
+// Cell *c = module->addAndGate(NEW_ID, A, B, Y);
+// c->type = chain.back().first->type;
+endmatch
+
+code
+ if (next) {
+ if (next->type.in(\FDRE, \FDRE_1)) {
+ for (auto p : { \R })
+ if (port(next, p) != port(first, p))
+ reject;
+
+ if (next->type == \FDRE) {
+ for (auto p : { \IS_C_INVERTED, \IS_D_INVERTED, \IS_R_INVERTED }) {
+ auto n = next->parameters.at(p, default_params.at(std::make_pair(next->type,p)));
+ auto f = first->parameters.at(p, default_params.at(std::make_pair(first->type,p)));
+ if (n != f)
+ reject;
+ }
+ }
+ }
+
+ chain.push_back(next);
+ subpattern(tail);
+ } else {
+ if (GetSize(chain) > GetSize(longest_chain))
+ longest_chain = chain;
+ }
+finally
+ if (next)
+ chain.pop_back();
+endcode
+
+// -----------
+
+pattern variable
+
+state <int> shiftx_width
+udata <int> minlen
+udata <vector<Cell*>> chain
+
+match shiftx
+ select shiftx->type.in($shiftx)
+ select !shiftx->has_keep_attr()
+ select param(shiftx, \Y_WIDTH).as_int() == 1
+ filter param(shiftx, \A_WIDTH).as_int() >= minlen
+endmatch
+
+code shiftx_width
+ shiftx_width = param(shiftx, \A_WIDTH).as_int();
+endcode
+
+match first
+ select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_)
+ select nusers(port(first, \Q)) == 2
+ index <SigBit> port(first, \Q) === port(shiftx, \A)[shiftx_width-1]
+endmatch
+
+code
+ chain.push_back(first);
+ subpattern(tail);
+finally
+ if (GetSize(chain) == shiftx_width)
+ accept;
+ chain.clear();
+endcode
+
+// ------------------------------------------------------------------
+
+subpattern tail
+arg shiftx
+arg shiftx_width
+
+match next
+ semioptional
+ select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_)
+ select !next->has_keep_attr()
+ select !port(next, \D)[0].wire->get_bool_attribute(\keep)
+ select nusers(port(next, \Q)) == 3
+ index <IdString> next->type === chain.back()->type
+ index <SigBit> port(next, \Q) === port(chain.back(), \D)
+ index <SigBit> port(next, \Q) === port(shiftx, \A)[shiftx_width-1-GetSize(chain)]
+endmatch
+
+code
+ if (next) {
+ auto sig = port(next, \Q);
+ log_warning("nusers of '%s'\n", log_signal(sig));
+ for (auto bit : sigmap(sig))
+ for (auto user : sigusers[bit])
+ log_warning("\t%s\n", log_id(user));
+ chain.push_back(next);
+ if (GetSize(chain) < shiftx_width)
+ subpattern(tail);
+ }
+endcode