xilinx_srl to support FDRE and FDRE_1
authorEddie Hung <eddie@fpgeh.com>
Wed, 21 Aug 2019 22:35:29 +0000 (15:35 -0700)
committerEddie Hung <eddie@fpgeh.com>
Wed, 21 Aug 2019 22:35:29 +0000 (15:35 -0700)
passes/pmgen/xilinx_srl.cc
passes/pmgen/xilinx_srl.pmg

index bd4dc59ab21b94862dba80fd4e4f153c8664d4f8..862b44bb02ed73964a16a5ded7d00dfa216a9739 100644 (file)
@@ -34,6 +34,10 @@ void reduce_chain(xilinx_srl_pm &pm)
 {
        auto &st = pm.st_reduce;
        auto &ud = pm.ud_reduce;
+       auto param_def = [&ud](Cell *cell, IdString param) {
+               auto def = ud.default_params.at(std::make_pair(cell->type,param));
+               return cell->parameters.at(param, def);
+       };
 
        log("Found chain of length %d (%s):\n", GetSize(ud.longest_chain), log_id(st.first->type));
 
@@ -42,14 +46,20 @@ void reduce_chain(xilinx_srl_pm &pm)
        SigSpec initval;
        for (auto cell : ud.longest_chain) {
                log_debug("    %s\n", log_id(cell));
-               SigBit Q = cell->getPort(ID(Q));
-               log_assert(Q.wire);
-               auto it = Q.wire->attributes.find(ID(init));
-               if (it != Q.wire->attributes.end()) {
-                       initval.append(it->second[Q.offset]);
+               if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) {
+                       SigBit Q = cell->getPort(ID(Q));
+                       log_assert(Q.wire);
+                       auto it = Q.wire->attributes.find(ID(init));
+                       if (it != Q.wire->attributes.end()) {
+                               initval.append(it->second[Q.offset]);
+                       }
+                       else
+                               initval.append(State::Sx);
                }
+               else if (cell->type.in(ID(FDRE), ID(FDRE_1)))
+                       initval.append(param_def(cell, ID(INIT)));
                else
-                       initval.append(State::Sx);
+                       log_abort();
                if (cell != last_cell)
                        pm.autoremove(cell);
        }
@@ -66,6 +76,8 @@ void reduce_chain(xilinx_srl_pm &pm)
                        c->setParam(ID(CLKPOL), 1);
                else if (c->type.in(ID($_DFF_N_), ID($DFFE_NN_), ID($_DFFE_NP_), ID(FDRE_1)))
                        c->setParam(ID(CLKPOL), 0);
+               else if (c->type.in(ID(FDRE)))
+                       c->setParam(ID(CLKPOL), param_def(c, ID(IS_C_INVERTED)).as_bool() ? 0 : 1);
                else
                        log_abort();
                if (c->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)))
@@ -119,6 +131,11 @@ struct XilinxSrlPass : public Pass {
                        do {
                                auto pm = xilinx_srl_pm(module, module->selected_cells());
                                pm.ud_reduce.minlen = minlen;
+                               // TODO: How to get these automatically?
+                               pm.ud_reduce.default_params[std::make_pair(ID(FDRE),ID(INIT))] = State::S0;
+                               pm.ud_reduce.default_params[std::make_pair(ID(FDRE),ID(IS_C_INVERTED))] = State::S0;
+                               pm.ud_reduce.default_params[std::make_pair(ID(FDRE),ID(IS_D_INVERTED))] = State::S0;
+                               pm.ud_reduce.default_params[std::make_pair(ID(FDRE),ID(IS_R_INVERTED))] = State::S0;
                                did_something = pm.run_reduce(reduce_chain);
                        } while (did_something);
                }
index 3a20966535887b01012a8d8eeba9310934fc2e1a..5ae7690c8ef57516041ea5f3243bf273eb81683c 100644 (file)
@@ -3,6 +3,7 @@ pattern reduce
 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();
@@ -12,7 +13,6 @@ endcode
 match first
        select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1)
        select !first->get_bool_attribute(\keep)
-       select !port(first, \Q)[0].wire->get_bool_attribute(\keep)
        filter !non_first_cells.count(first)
 //generate
 //     SigSpec A = module->addWire(NEW_ID);
@@ -50,19 +50,50 @@ 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->get_bool_attribute(\keep)
-       select !port(first, \Q)[0].wire->get_bool_attribute(\keep)
 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->get_bool_attribute(\keep)
-       select !port(next, \Q)[0].wire->get_bool_attribute(\keep)
+       select !port(next, \D)[0].wire->get_bool_attribute(\keep)
        select nusers(port(next, \Q)) == 2
        index <IdString> next->type === first->type
        index <SigSpec> 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
 
@@ -75,7 +106,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->get_bool_attribute(\keep)
-       select !port(next, \Q)[0].wire->get_bool_attribute(\keep)
+       select !port(next, \D)[0].wire->get_bool_attribute(\keep)
        select nusers(port(next, \Q)) == 2
        index <IdString> next->type === chain.back()->type
        index <SigSpec> port(next, \Q) === port(chain.back(), \D)
@@ -89,6 +120,21 @@ 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 {