pattern fixed udata > chain longest_chain udata > non_first_cells udata minlen udata ,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 next->type === first->type index 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 next->type === chain.back()->type index 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 shiftx_width state slice udata minlen udata >> 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_, $dff, $dffe) select !first->has_keep_attr() slice idx GetSize(port(first, \Q)) select nusers(port(first, \Q)[idx], false /* unique */) == 2 index port(first, \Q)[idx] === port(shiftx, \A)[shiftx_width-1] set slice idx endmatch code chain.emplace_back(first, slice); subpattern(tail); finally if (GetSize(chain) == shiftx_width) accept; chain.clear(); endcode // ------------------------------------------------------------------ subpattern tail arg shiftx arg shiftx_width arg slice 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) slice idx GetSize(port(next, \Q)) select nusers(port(next, \Q)[idx], false /* unique */) == 3 index next->type === chain.back().first->type index port(next, \Q)[idx] === port(chain.back().first, \D)[chain.back().second] index port(next, \Q)[idx] === port(shiftx, \A)[shiftx_width-1-GetSize(chain)] set slice idx endmatch code if (next) { chain.emplace_back(next, slice); if (GetSize(chain) < shiftx_width) subpattern(tail); } endcode