#ifndef NEWCELLTYPES_H #define NEWCELLTYPES_H #include "kernel/rtlil.h" #include "kernel/yosys.h" YOSYS_NAMESPACE_BEGIN /** * This API is unstable. * It may change or be removed in future versions and break dependent code. */ namespace StaticCellTypes { // Given by last internal cell type IdString constids.inc, compilation error if too low constexpr int MAX_CELLS = 300; // Currently given by _MUX16_, compilation error if too low constexpr int MAX_PORTS = 20; struct CellTableBuilder { struct PortList { std::array ports{}; size_t count = 0; constexpr PortList() = default; constexpr PortList(std::initializer_list init) { for (auto p : init) { ports[count++] = p; } } constexpr auto begin() const { return ports.begin(); } constexpr auto end() const { return ports.begin() + count; } constexpr bool contains(TwineRef port) const { for (size_t i = 0; i < count; i++) { if (port == ports[i]) return true; } return false; } constexpr size_t size() const { return count; } }; struct Features { bool is_evaluable = false; bool is_combinatorial = false; bool is_synthesizable = false; bool is_stdcell = false; bool is_ff = false; bool is_mem_noff = false; bool is_anyinit = false; bool is_tristate = false; }; struct CellInfo { RTLIL::IdString type; PortList inputs, outputs; Features features; }; std::array cells{}; size_t count = 0; constexpr void setup_type(RTLIL::IdString type, std::initializer_list inputs, std::initializer_list outputs, const Features& features) { cells[count++] = {type, PortList(inputs), PortList(outputs), features}; } constexpr void setup_internals_other() { Features features {}; features.is_tristate = true; setup_type(ID($tribuf), {TW::A, TW::EN}, {TW::Y}, features); features = {}; setup_type(ID($assert), {TW::A, TW::EN}, {}, features); setup_type(ID($assume), {TW::A, TW::EN}, {}, features); setup_type(ID($live), {TW::A, TW::EN}, {}, features); setup_type(ID($fair), {TW::A, TW::EN}, {}, features); setup_type(ID($cover), {TW::A, TW::EN}, {}, features); setup_type(ID($initstate), {}, {TW::Y}, features); setup_type(ID($anyconst), {}, {TW::Y}, features); setup_type(ID($anyseq), {}, {TW::Y}, features); setup_type(ID($allconst), {}, {TW::Y}, features); setup_type(ID($allseq), {}, {TW::Y}, features); setup_type(ID($equiv), {TW::A, TW::B}, {TW::Y}, features); setup_type(ID($specify2), {TW::EN, TW::SRC, TW::DST}, {}, features); setup_type(ID($specify3), {TW::EN, TW::SRC, TW::DST, TW::DAT}, {}, features); setup_type(ID($specrule), {TW::SRC_EN, TW::DST_EN, TW::SRC, TW::DST}, {}, features); setup_type(ID($print), {TW::EN, TW::ARGS, TW::TRG}, {}, features); setup_type(ID($check), {TW::A, TW::EN, TW::ARGS, TW::TRG}, {}, features); setup_type(ID($set_tag), {TW::A, TW::SET, TW::CLR}, {TW::Y}, features); setup_type(ID($get_tag), {TW::A}, {TW::Y}, features); setup_type(ID($overwrite_tag), {TW::A, TW::SET, TW::CLR}, {}, features); setup_type(ID($original_tag), {TW::A}, {TW::Y}, features); setup_type(ID($future_ff), {TW::A}, {TW::Y}, features); setup_type(ID($scopeinfo), {}, {}, features); setup_type(ID($input_port), {}, {TW::Y}, features); setup_type(ID($output_port), {TW::A}, {}, features); setup_type(ID($public), {TW::A}, {}, features); setup_type(ID($connect), {TW::A, TW::B}, {}, features); } constexpr void setup_internals_eval() { Features features {}; features.is_evaluable = true; std::initializer_list unary_ops = { ID($not), ID($pos), ID($buf), ID($neg), ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($logic_not), ID($slice), ID($lut), ID($sop) }; std::initializer_list binary_ops = { ID($and), ID($or), ID($xor), ID($xnor), ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx), ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt), ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow), ID($logic_and), ID($logic_or), ID($concat), ID($macc), ID($bweqx) }; for (auto type : unary_ops) setup_type(type, {TW::A}, {TW::Y}, features); for (auto type : binary_ops) setup_type(type, {TW::A, TW::B}, {TW::Y}, features); for (auto type : {ID($mux), ID($pmux), ID($bwmux)}) setup_type(type, {TW::A, TW::B, TW::S}, {TW::Y}, features); for (auto type : {ID($bmux), ID($demux)}) setup_type(type, {TW::A, TW::S}, {TW::Y}, features); setup_type(ID($lcu), {TW::P, TW::G, TW::CI}, {TW::CO}, features); setup_type(ID($alu), {TW::A, TW::B, TW::CI, TW::BI}, {TW::X, TW::Y, TW::CO}, features); setup_type(ID($macc_v2), {TW::A, TW::B, TW::C}, {TW::Y}, features); setup_type(ID($fa), {TW::A, TW::B, TW::C}, {TW::X, TW::Y}, features); } constexpr void setup_internals_ff() { Features features {}; features.is_ff = true; setup_type(ID($sr), {TW::SET, TW::CLR}, {TW::Q}, features); setup_type(ID($ff), {TW::D}, {TW::Q}, features); setup_type(ID($dff), {TW::CLK, TW::D}, {TW::Q}, features); setup_type(ID($dffe), {TW::CLK, TW::EN, TW::D}, {TW::Q}, features); setup_type(ID($dffsr), {TW::CLK, TW::SET, TW::CLR, TW::D}, {TW::Q}, features); setup_type(ID($dffsre), {TW::CLK, TW::SET, TW::CLR, TW::D, TW::EN}, {TW::Q}, features); setup_type(ID($adff), {TW::CLK, TW::ARST, TW::D}, {TW::Q}, features); setup_type(ID($adffe), {TW::CLK, TW::ARST, TW::D, TW::EN}, {TW::Q}, features); setup_type(ID($aldff), {TW::CLK, TW::ALOAD, TW::AD, TW::D}, {TW::Q}, features); setup_type(ID($aldffe), {TW::CLK, TW::ALOAD, TW::AD, TW::D, TW::EN}, {TW::Q}, features); setup_type(ID($sdff), {TW::CLK, TW::SRST, TW::D}, {TW::Q}, features); setup_type(ID($sdffe), {TW::CLK, TW::SRST, TW::D, TW::EN}, {TW::Q}, features); setup_type(ID($sdffce), {TW::CLK, TW::SRST, TW::D, TW::EN}, {TW::Q}, features); setup_type(ID($dlatch), {TW::EN, TW::D}, {TW::Q}, features); setup_type(ID($adlatch), {TW::EN, TW::D, TW::ARST}, {TW::Q}, features); setup_type(ID($dlatchsr), {TW::EN, TW::SET, TW::CLR, TW::D}, {TW::Q}, features); } constexpr void setup_internals_anyinit() { Features features {}; features.is_anyinit = true; setup_type(ID($anyinit), {TW::D}, {TW::Q}, features); } constexpr void setup_internals_mem_noff() { Features features {}; features.is_mem_noff = true; // NOT setup_internals_ff() setup_type(ID($memrd), {TW::CLK, TW::EN, TW::ADDR}, {TW::DATA}, features); setup_type(ID($memrd_v2), {TW::CLK, TW::EN, TW::ARST, TW::SRST, TW::ADDR}, {TW::DATA}, features); setup_type(ID($memwr), {TW::CLK, TW::EN, TW::ADDR, TW::DATA}, {}, features); setup_type(ID($memwr_v2), {TW::CLK, TW::EN, TW::ADDR, TW::DATA}, {}, features); setup_type(ID($meminit), {TW::ADDR, TW::DATA}, {}, features); setup_type(ID($meminit_v2), {TW::ADDR, TW::DATA, TW::EN}, {}, features); setup_type(ID($mem), {TW::RD_CLK, TW::RD_EN, TW::RD_ADDR, TW::WR_CLK, TW::WR_EN, TW::WR_ADDR, TW::WR_DATA}, {TW::RD_DATA}, features); setup_type(ID($mem_v2), {TW::RD_CLK, TW::RD_EN, TW::RD_ARST, TW::RD_SRST, TW::RD_ADDR, TW::WR_CLK, TW::WR_EN, TW::WR_ADDR, TW::WR_DATA}, {TW::RD_DATA}, features); // What? setup_type(ID($fsm), {TW::CLK, TW::ARST, TW::CTRL_IN}, {TW::CTRL_OUT}, features); } constexpr void setup_stdcells_tristate() { Features features {}; features.is_stdcell = true; features.is_tristate = true; setup_type(ID($_TBUF_), {TW::A, TW::E}, {TW::Y}, features); } constexpr void setup_stdcells_eval() { Features features {}; features.is_stdcell = true; features.is_evaluable = true; setup_type(ID($_BUF_), {TW::A}, {TW::Y}, features); setup_type(ID($_NOT_), {TW::A}, {TW::Y}, features); setup_type(ID($_AND_), {TW::A, TW::B}, {TW::Y}, features); setup_type(ID($_NAND_), {TW::A, TW::B}, {TW::Y}, features); setup_type(ID($_OR_), {TW::A, TW::B}, {TW::Y}, features); setup_type(ID($_NOR_), {TW::A, TW::B}, {TW::Y}, features); setup_type(ID($_XOR_), {TW::A, TW::B}, {TW::Y}, features); setup_type(ID($_XNOR_), {TW::A, TW::B}, {TW::Y}, features); setup_type(ID($_ANDNOT_), {TW::A, TW::B}, {TW::Y}, features); setup_type(ID($_ORNOT_), {TW::A, TW::B}, {TW::Y}, features); setup_type(ID($_MUX_), {TW::A, TW::B, TW::S}, {TW::Y}, features); setup_type(ID($_NMUX_), {TW::A, TW::B, TW::S}, {TW::Y}, features); setup_type(ID($_MUX4_), {TW::A, TW::B, TW::C, TW::D, TW::S, TW::T}, {TW::Y}, features); setup_type(ID($_MUX8_), {TW::A, TW::B, TW::C, TW::D, TW::E, TW::F, TW::G, TW::H, TW::S, TW::T, TW::U}, {TW::Y}, features); setup_type(ID($_MUX16_), {TW::A, TW::B, TW::C, TW::D, TW::E, TW::F, TW::G, TW::H, TW::I, TW::J, TW::K, TW::L, TW::M, TW::N, TW::O, TW::P, TW::S, TW::T, TW::U, TW::V}, {TW::Y}, features); setup_type(ID($_AOI3_), {TW::A, TW::B, TW::C}, {TW::Y}, features); setup_type(ID($_OAI3_), {TW::A, TW::B, TW::C}, {TW::Y}, features); setup_type(ID($_AOI4_), {TW::A, TW::B, TW::C, TW::D}, {TW::Y}, features); setup_type(ID($_OAI4_), {TW::A, TW::B, TW::C, TW::D}, {TW::Y}, features); } constexpr void setup_stdcells_ff() { Features features {}; features.is_stdcell = true; features.is_ff = true; // for (auto c1 : list_np) // for (auto c2 : list_np) // setup_type(std::string("$_SR_") + c1 + c2 + "_", {TW::S, TW::R}, {TW::Q}, features); setup_type(ID($_SR_NN_), {TW::S, TW::R}, {TW::Q}, features); setup_type(ID($_SR_NP_), {TW::S, TW::R}, {TW::Q}, features); setup_type(ID($_SR_PN_), {TW::S, TW::R}, {TW::Q}, features); setup_type(ID($_SR_PP_), {TW::S, TW::R}, {TW::Q}, features); setup_type(ID($_FF_), {TW::D}, {TW::Q}, features); // for (auto c1 : list_np) // setup_type(std::string("$_DFF_") + c1 + "_", {TW::C, TW::D}, {TW::Q}, features); setup_type(ID::$_DFF_N_, {TW::C, TW::D}, {TW::Q}, features); setup_type(ID::$_DFF_P_, {TW::C, TW::D}, {TW::Q}, features); // for (auto c1 : list_np) // for (auto c2 : list_np) // setup_type(std::string("$_DFFE_") + c1 + c2 + "_", {TW::C, TW::D, TW::E}, {TW::Q}, features); setup_type(ID::$_DFFE_NN_, {TW::C, TW::D, TW::E}, {TW::Q}, features); setup_type(ID::$_DFFE_NP_, {TW::C, TW::D, TW::E}, {TW::Q}, features); setup_type(ID::$_DFFE_PN_, {TW::C, TW::D, TW::E}, {TW::Q}, features); setup_type(ID::$_DFFE_PP_, {TW::C, TW::D, TW::E}, {TW::Q}, features); // for (auto c1 : list_np) // for (auto c2 : list_np) // for (auto c3 : list_01) // setup_type(std::string("$_DFF_") + c1 + c2 + c3 + "_", {TW::C, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DFF_NN0_), {TW::C, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DFF_NN1_), {TW::C, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DFF_NP0_), {TW::C, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DFF_NP1_), {TW::C, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DFF_PN0_), {TW::C, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DFF_PN1_), {TW::C, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DFF_PP0_), {TW::C, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DFF_PP1_), {TW::C, TW::R, TW::D}, {TW::Q}, features); // for (auto c1 : list_np) // for (auto c2 : list_np) // for (auto c3 : list_01) // for (auto c4 : list_np) // setup_type(std::string("$_DFFE_") + c1 + c2 + c3 + c4 + "_", {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFE_NN0N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFE_NN0P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFE_NN1N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFE_NN1P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFE_NP0N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFE_NP0P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFE_NP1N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFE_NP1P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFE_PN0N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFE_PN0P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFE_PN1N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFE_PN1P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFE_PP0N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFE_PP0P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFE_PP1N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFE_PP1P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); // for (auto c1 : list_np) // for (auto c2 : list_np) // setup_type(std::string("$_ALDFF_") + c1 + c2 + "_", {TW::C, TW::L, TW::AD, TW::D}, {TW::Q}, features); setup_type(ID($_ALDFF_NN_), {TW::C, TW::L, TW::AD, TW::D}, {TW::Q}, features); setup_type(ID($_ALDFF_NP_), {TW::C, TW::L, TW::AD, TW::D}, {TW::Q}, features); setup_type(ID($_ALDFF_PN_), {TW::C, TW::L, TW::AD, TW::D}, {TW::Q}, features); setup_type(ID($_ALDFF_PP_), {TW::C, TW::L, TW::AD, TW::D}, {TW::Q}, features); // for (auto c1 : list_np) // for (auto c2 : list_np) // for (auto c3 : list_np) // setup_type(std::string("$_ALDFFE_") + c1 + c2 + c3 + "_", {TW::C, TW::L, TW::AD, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_ALDFFE_NNN_), {TW::C, TW::L, TW::AD, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_ALDFFE_NNP_), {TW::C, TW::L, TW::AD, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_ALDFFE_NPN_), {TW::C, TW::L, TW::AD, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_ALDFFE_NPP_), {TW::C, TW::L, TW::AD, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_ALDFFE_PNN_), {TW::C, TW::L, TW::AD, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_ALDFFE_PNP_), {TW::C, TW::L, TW::AD, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_ALDFFE_PPN_), {TW::C, TW::L, TW::AD, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_ALDFFE_PPP_), {TW::C, TW::L, TW::AD, TW::D, TW::E}, {TW::Q}, features); // for (auto c1 : list_np) // for (auto c2 : list_np) // for (auto c3 : list_np) // setup_type(std::string("$_DFFSR_") + c1 + c2 + c3 + "_", {TW::C, TW::S, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DFFSR_NNN_), {TW::C, TW::S, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DFFSR_NNP_), {TW::C, TW::S, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DFFSR_NPN_), {TW::C, TW::S, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DFFSR_NPP_), {TW::C, TW::S, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DFFSR_PNN_), {TW::C, TW::S, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DFFSR_PNP_), {TW::C, TW::S, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DFFSR_PPN_), {TW::C, TW::S, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DFFSR_PPP_), {TW::C, TW::S, TW::R, TW::D}, {TW::Q}, features); // for (auto c1 : list_np) // for (auto c2 : list_np) // for (auto c3 : list_np) // for (auto c4 : list_np) // setup_type(std::string("$_DFFSRE_") + c1 + c2 + c3 + c4 + "_", {TW::C, TW::S, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFSRE_NNNN_), {TW::C, TW::S, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFSRE_NNNP_), {TW::C, TW::S, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFSRE_NNPN_), {TW::C, TW::S, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFSRE_NNPP_), {TW::C, TW::S, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFSRE_NPNN_), {TW::C, TW::S, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFSRE_NPNP_), {TW::C, TW::S, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFSRE_NPPN_), {TW::C, TW::S, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFSRE_NPPP_), {TW::C, TW::S, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFSRE_PNNN_), {TW::C, TW::S, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFSRE_PNNP_), {TW::C, TW::S, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFSRE_PNPN_), {TW::C, TW::S, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFSRE_PNPP_), {TW::C, TW::S, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFSRE_PPNN_), {TW::C, TW::S, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFSRE_PPNP_), {TW::C, TW::S, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFSRE_PPPN_), {TW::C, TW::S, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_DFFSRE_PPPP_), {TW::C, TW::S, TW::R, TW::D, TW::E}, {TW::Q}, features); // for (auto c1 : list_np) // for (auto c2 : list_np) // for (auto c3 : list_01) // setup_type(std::string("$_SDFF_") + c1 + c2 + c3 + "_", {TW::C, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_SDFF_NN0_), {TW::C, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_SDFF_NN1_), {TW::C, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_SDFF_NP0_), {TW::C, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_SDFF_NP1_), {TW::C, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_SDFF_PN0_), {TW::C, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_SDFF_PN1_), {TW::C, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_SDFF_PP0_), {TW::C, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_SDFF_PP1_), {TW::C, TW::R, TW::D}, {TW::Q}, features); // for (auto c1 : list_np) // for (auto c2 : list_np) // for (auto c3 : list_01) // for (auto c4 : list_np) // setup_type(std::string("$_SDFFE_") + c1 + c2 + c3 + c4 + "_", {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFE_NN0N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFE_NN0P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFE_NN1N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFE_NN1P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFE_NP0N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFE_NP0P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFE_NP1N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFE_NP1P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFE_PN0N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFE_PN0P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFE_PN1N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFE_PN1P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFE_PP0N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFE_PP0P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFE_PP1N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFE_PP1P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); // for (auto c1 : list_np) // for (auto c2 : list_np) // for (auto c3 : list_01) // for (auto c4 : list_np) // setup_type(std::string("$_SDFFCE_") + c1 + c2 + c3 + c4 + "_", {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFCE_NN0N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFCE_NN0P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFCE_NN1N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFCE_NN1P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFCE_NP0N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFCE_NP0P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFCE_NP1N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFCE_NP1P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFCE_PN0N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFCE_PN0P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFCE_PN1N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFCE_PN1P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFCE_PP0N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFCE_PP0P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFCE_PP1N_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); setup_type(ID($_SDFFCE_PP1P_), {TW::C, TW::R, TW::D, TW::E}, {TW::Q}, features); // for (auto c1 : list_np) // setup_type(std::string("$_DLATCH_") + c1 + "_", {TW::E, TW::D}, {TW::Q}, features); setup_type(ID($_DLATCH_N_), {TW::E, TW::D}, {TW::Q}, features); setup_type(ID($_DLATCH_P_), {TW::E, TW::D}, {TW::Q}, features); // for (auto c1 : list_np) // for (auto c2 : list_np) // for (auto c3 : list_01) // setup_type(std::string("$_DLATCH_") + c1 + c2 + c3 + "_", {TW::E, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DLATCH_NN0_), {TW::E, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DLATCH_NN1_), {TW::E, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DLATCH_NP0_), {TW::E, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DLATCH_NP1_), {TW::E, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DLATCH_PN0_), {TW::E, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DLATCH_PN1_), {TW::E, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DLATCH_PP0_), {TW::E, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DLATCH_PP1_), {TW::E, TW::R, TW::D}, {TW::Q}, features); // for (auto c1 : list_np) // for (auto c2 : list_np) // for (auto c3 : list_np) // setup_type(std::string("$_DLATCHSR_") + c1 + c2 + c3 + "_", {TW::E, TW::S, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DLATCHSR_NNN_), {TW::E, TW::S, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DLATCHSR_NNP_), {TW::E, TW::S, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DLATCHSR_NPN_), {TW::E, TW::S, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DLATCHSR_NPP_), {TW::E, TW::S, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DLATCHSR_PNN_), {TW::E, TW::S, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DLATCHSR_PNP_), {TW::E, TW::S, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DLATCHSR_PPN_), {TW::E, TW::S, TW::R, TW::D}, {TW::Q}, features); setup_type(ID($_DLATCHSR_PPP_), {TW::E, TW::S, TW::R, TW::D}, {TW::Q}, features); } constexpr CellTableBuilder() { setup_internals_other(); setup_internals_eval(); setup_internals_ff(); setup_internals_anyinit(); setup_internals_mem_noff(); setup_stdcells_tristate(); setup_stdcells_eval(); setup_stdcells_ff(); } }; constexpr CellTableBuilder builder {}; struct PortInfo { struct PortLists { std::array data{}; constexpr CellTableBuilder::PortList operator()(IdString type) const { return data[type.index_]; } constexpr CellTableBuilder::PortList& operator[](size_t idx) { return data[idx]; } constexpr size_t size() const { return data.size(); } }; PortLists inputs {}; PortLists outputs {}; constexpr PortInfo() { for (size_t i = 0; i < builder.count; ++i) { auto& cell = builder.cells[i]; size_t idx = cell.type.index_; inputs[idx] = cell.inputs; outputs[idx] = cell.outputs; } } }; struct Categories { struct Category { std::array data{}; constexpr bool operator()(IdString type) const { size_t idx = type.index_; if (idx >= MAX_CELLS) return false; return data[idx]; } constexpr bool operator[](size_t idx) { return data[idx]; } constexpr void set_id(IdString type, bool val = true) { size_t idx = type.index_; if (idx >= MAX_CELLS) return; // TODO should be an assert but then it's not constexpr data[idx] = val; } constexpr void set(size_t idx, bool val = true) { data[idx] = val; } constexpr size_t size() const { return data.size(); } }; Category empty {}; Category is_known {}; Category is_evaluable {}; Category is_combinatorial {}; Category is_synthesizable {}; Category is_stdcell {}; Category is_ff {}; Category is_mem_noff {}; Category is_anyinit {}; Category is_tristate {}; constexpr Categories() { for (size_t i = 0; i < builder.count; ++i) { auto& cell = builder.cells[i]; size_t idx = cell.type.index_; is_known.set(idx); is_evaluable.set(idx, cell.features.is_evaluable); is_combinatorial.set(idx, cell.features.is_combinatorial); is_synthesizable.set(idx, cell.features.is_synthesizable); is_stdcell.set(idx, cell.features.is_stdcell); is_ff.set(idx, cell.features.is_ff); is_mem_noff.set(idx, cell.features.is_mem_noff); is_anyinit.set(idx, cell.features.is_anyinit); is_tristate.set(idx, cell.features.is_tristate); } } constexpr static Category join(Category left, Category right) { Category c {}; for (size_t i = 0; i < MAX_CELLS; ++i) { c.set(i, left[i] || right[i]); } return c; } constexpr static Category meet(Category left, Category right) { Category c {}; for (size_t i = 0; i < MAX_CELLS; ++i) { c.set(i, left[i] && right[i]); } return c; } // Sketchy! Make sure to always meet with only the known universe. // In other words, no modus tollens allowed constexpr static Category complement(Category arg) { Category c {}; for (size_t i = 0; i < MAX_CELLS; ++i) { c.set(i, !arg[i]); } return c; } }; // Pure static constexpr PortInfo port_info; static constexpr Categories categories; // Legacy namespace Compat { static constexpr auto internals_all = Categories::meet(categories.is_known, Categories::complement(categories.is_stdcell)); static constexpr auto mem_ff = Categories::join(categories.is_ff, categories.is_mem_noff); // old setup_internals + setup_stdcells static constexpr auto nomem_noff = Categories::meet(categories.is_known, Categories::complement(mem_ff)); static constexpr auto internals_mem_ff = Categories::meet(internals_all, mem_ff); // old setup_internals static constexpr auto internals_nomem_noff = Categories::meet(internals_all, nomem_noff); // old setup_stdcells static constexpr auto stdcells_nomem_noff = Categories::meet(categories.is_stdcell, nomem_noff); static constexpr auto stdcells_mem = Categories::meet(categories.is_stdcell, categories.is_mem_noff); // old setup_internals_eval // static constexpr auto internals_eval = Categories::meet(internals_all, categories.is_evaluable); }; namespace { static_assert(categories.is_evaluable(ID($and))); static_assert(!categories.is_ff(ID($and))); static_assert(Categories::join(categories.is_evaluable, categories.is_ff)(ID($and))); static_assert(Categories::join(categories.is_evaluable, categories.is_ff)(ID($dffsr))); static_assert(!Categories::join(categories.is_evaluable, categories.is_ff)(ID($anyinit))); } }; struct NewCellType { RTLIL::IdString type; pool inputs, outputs; bool is_evaluable; bool is_combinatorial; bool is_synthesizable; }; struct NewCellTypes { struct IdStringHash { std::size_t operator()(const IdString id) const { return static_cast(id.hash_top().yield()); } }; StaticCellTypes::Categories::Category static_cell_types = StaticCellTypes::categories.empty; std::unordered_map custom_cell_types {}; NewCellTypes() { static_cell_types = StaticCellTypes::categories.empty; } NewCellTypes(RTLIL::Design *design) { static_cell_types = StaticCellTypes::categories.empty; setup(design); } void setup(RTLIL::Design *design = NULL) { if (design) setup_design(design); static_cell_types = StaticCellTypes::categories.is_known; } void setup_design(RTLIL::Design *design) { for (auto module : design->modules()) setup_module(module); } void setup_module(RTLIL::Module *module) { pool inputs, outputs; for (auto wire_name : module->ports) { RTLIL::Wire *wire = module->wire(wire_name); if (wire->port_input) inputs.insert(wire->meta_->name_id); if (wire->port_output) outputs.insert(wire->meta_->name_id); } setup_type(module->name, inputs, outputs); } void setup_type(RTLIL::IdString type, const pool &inputs, const pool &outputs, bool is_evaluable = false, bool is_combinatorial = false, bool is_synthesizable = false) { NewCellType ct = {type, inputs, outputs, is_evaluable, is_combinatorial, is_synthesizable}; custom_cell_types[ct.type] = ct; } void clear() { custom_cell_types.clear(); static_cell_types = StaticCellTypes::categories.empty; } bool cell_known(const RTLIL::IdString &type) const { return static_cell_types(type) || custom_cell_types.count(type) != 0; } bool cell_output(const RTLIL::IdString &type, TwineRef port) const { // TODO refactor if (static_cell_types(type) && StaticCellTypes::port_info.outputs(type).contains(port)) { return true; } auto it = custom_cell_types.find(type); return it != custom_cell_types.end() && it->second.outputs.count(port) != 0; } bool cell_input(const RTLIL::IdString &type, TwineRef port) const { if (static_cell_types(type) && StaticCellTypes::port_info.inputs(type).contains(port)) { return true; } auto it = custom_cell_types.find(type); return it != custom_cell_types.end() && it->second.inputs.count(port) != 0; } RTLIL::PortDir cell_port_dir(RTLIL::IdString type, TwineRef port) const { bool is_input, is_output; if (static_cell_types(type)) { is_input = StaticCellTypes::port_info.inputs(type).contains(port); is_output = StaticCellTypes::port_info.outputs(type).contains(port); } else { auto it = custom_cell_types.find(type); if (it == custom_cell_types.end()) return RTLIL::PD_UNKNOWN; is_input = it->second.inputs.count(port); is_output = it->second.outputs.count(port); } return RTLIL::PortDir(is_input + is_output * 2); } bool cell_evaluable(const RTLIL::IdString &type) const { return static_cell_types(type) && StaticCellTypes::categories.is_evaluable(type); } }; extern NewCellTypes yosys_celltypes; YOSYS_NAMESPACE_END #endif