From e6c3a7e87fc92f8fbe57fe679171a4307c2d05d8 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 21 Feb 2025 16:05:53 +1300 Subject: [PATCH 01/10] celltypes: add builtin_ff and formal --- kernel/celltypes.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 3167a9add..04edc20e6 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -31,6 +31,8 @@ struct CellType bool is_evaluable; bool is_combinatorial; bool is_synthesizable; + bool is_builtin_ff; + bool is_formal; }; struct CellTypes @@ -58,9 +60,11 @@ struct CellTypes setup_stdcells_mem(); } - void setup_type(RTLIL::IdString type, const pool &inputs, const pool &outputs, bool is_evaluable = false, bool is_combinatorial = false, bool is_synthesizable = false) + void setup_type(RTLIL::IdString type, const pool &inputs, const pool &outputs, + bool is_evaluable = false, bool is_combinatorial = false, bool is_synthesizable = false, + bool is_builtin_ff = false, bool is_formal = false) { - CellType ct = {type, inputs, outputs, is_evaluable, is_combinatorial, is_synthesizable}; + CellType ct = {type, inputs, outputs, is_evaluable, is_combinatorial, is_synthesizable, is_builtin_ff, is_formal}; cell_types[ct.type] = ct; } From c1665ab416f4834c148127cad02d0189df5d9230 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 21 Feb 2025 16:08:53 +1300 Subject: [PATCH 02/10] celltypes: Add and use setup_type helpers Add `CellTypes::setup_{comb, ff, formal}_type()`. Most of the existing internal cells fit into one of these three groups. --- kernel/celltypes.h | 181 ++++++++++++++++++++++++++------------------- 1 file changed, 103 insertions(+), 78 deletions(-) diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 04edc20e6..08773b4eb 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -68,6 +68,24 @@ struct CellTypes cell_types[ct.type] = ct; } + // Setup combinational cell type which is evaluable and synthesizable + void setup_comb_type(RTLIL::IdString type, const pool &inputs, const pool &outputs) + { + setup_type(type, inputs, outputs, true, true, true, false, false); + } + + // Setup builtin ff cell type which is synthesizable + void setup_ff_type(RTLIL::IdString type, const pool &inputs, const pool &outputs) + { + setup_type(type, inputs, outputs, false, false, true, true, false); + } + + // Setup formal cell type which may be evaluable + void setup_formal_type(RTLIL::IdString type, const pool &inputs, const pool &outputs, bool is_evaluable = false) + { + setup_type(type, inputs, outputs, is_evaluable, false, false, false, true); + } + void setup_module(RTLIL::Module *module) { pool inputs, outputs; @@ -91,29 +109,36 @@ struct CellTypes { setup_internals_eval(); - setup_type(ID($tribuf), {ID::A, ID::EN}, {ID::Y}, true); + setup_comb_type(ID($tribuf), {ID::A, ID::EN}, {ID::Y}); - setup_type(ID($assert), {ID::A, ID::EN}, pool(), true); - setup_type(ID($assume), {ID::A, ID::EN}, pool(), true); - setup_type(ID($live), {ID::A, ID::EN}, pool(), true); - setup_type(ID($fair), {ID::A, ID::EN}, pool(), true); - setup_type(ID($cover), {ID::A, ID::EN}, pool(), true); - setup_type(ID($initstate), pool(), {ID::Y}, true); - setup_type(ID($anyconst), pool(), {ID::Y}, true); - setup_type(ID($anyseq), pool(), {ID::Y}, true); - setup_type(ID($allconst), pool(), {ID::Y}, true); - setup_type(ID($allseq), pool(), {ID::Y}, true); - setup_type(ID($equiv), {ID::A, ID::B}, {ID::Y}, true); + // evaluable formal + setup_formal_type(ID($assert), {ID::A, ID::EN}, pool(), true); + setup_formal_type(ID($assume), {ID::A, ID::EN}, pool(), true); + setup_formal_type(ID($live), {ID::A, ID::EN}, pool(), true); + setup_formal_type(ID($fair), {ID::A, ID::EN}, pool(), true); + setup_formal_type(ID($cover), {ID::A, ID::EN}, pool(), true); + setup_formal_type(ID($initstate), pool(), {ID::Y}, true); + setup_formal_type(ID($anyconst), pool(), {ID::Y}, true); + setup_formal_type(ID($anyseq), pool(), {ID::Y}, true); + setup_formal_type(ID($allconst), pool(), {ID::Y}, true); + setup_formal_type(ID($allseq), pool(), {ID::Y}, true); + setup_formal_type(ID($equiv), {ID::A, ID::B}, {ID::Y}, true); + + // evaluable non-formal setup_type(ID($specify2), {ID::EN, ID::SRC, ID::DST}, pool(), true); setup_type(ID($specify3), {ID::EN, ID::SRC, ID::DST, ID::DAT}, pool(), true); setup_type(ID($specrule), {ID::EN_SRC, ID::EN_DST, ID::SRC, ID::DST}, pool(), true); setup_type(ID($print), {ID::EN, ID::ARGS, ID::TRG}, pool()); - setup_type(ID($check), {ID::A, ID::EN, ID::ARGS, ID::TRG}, pool()); - setup_type(ID($set_tag), {ID::A, ID::SET, ID::CLR}, {ID::Y}); - setup_type(ID($get_tag), {ID::A}, {ID::Y}); - setup_type(ID($overwrite_tag), {ID::A, ID::SET, ID::CLR}, pool()); - setup_type(ID($original_tag), {ID::A}, {ID::Y}); - setup_type(ID($future_ff), {ID::A}, {ID::Y}); + + // non-evaluable formal + setup_formal_type(ID($check), {ID::A, ID::EN, ID::ARGS, ID::TRG}, pool()); + setup_formal_type(ID($set_tag), {ID::A, ID::SET, ID::CLR}, {ID::Y}); + setup_formal_type(ID($get_tag), {ID::A}, {ID::Y}); + setup_formal_type(ID($overwrite_tag), {ID::A, ID::SET, ID::CLR}, pool()); + setup_formal_type(ID($original_tag), {ID::A}, {ID::Y}); + setup_formal_type(ID($future_ff), {ID::A}, {ID::Y}); + + // non-evaluable non-formal setup_type(ID($scopeinfo), {}, {}); } @@ -135,45 +160,45 @@ struct CellTypes }; for (auto type : unary_ops) - setup_type(type, {ID::A}, {ID::Y}, true); + setup_comb_type(type, {ID::A}, {ID::Y}); for (auto type : binary_ops) - setup_type(type, {ID::A, ID::B}, {ID::Y}, true); + setup_comb_type(type, {ID::A, ID::B}, {ID::Y}); for (auto type : std::vector({ID($mux), ID($pmux), ID($bwmux)})) - setup_type(type, {ID::A, ID::B, ID::S}, {ID::Y}, true); + setup_comb_type(type, {ID::A, ID::B, ID::S}, {ID::Y}); for (auto type : std::vector({ID($bmux), ID($demux)})) - setup_type(type, {ID::A, ID::S}, {ID::Y}, true); + setup_comb_type(type, {ID::A, ID::S}, {ID::Y}); - setup_type(ID($lcu), {ID::P, ID::G, ID::CI}, {ID::CO}, true); - setup_type(ID($alu), {ID::A, ID::B, ID::CI, ID::BI}, {ID::X, ID::Y, ID::CO}, true); - setup_type(ID($fa), {ID::A, ID::B, ID::C}, {ID::X, ID::Y}, true); + setup_comb_type(ID($lcu), {ID::P, ID::G, ID::CI}, {ID::CO}); + setup_comb_type(ID($alu), {ID::A, ID::B, ID::CI, ID::BI}, {ID::X, ID::Y, ID::CO}); + setup_comb_type(ID($fa), {ID::A, ID::B, ID::C}, {ID::X, ID::Y}); } void setup_internals_ff() { - setup_type(ID($sr), {ID::SET, ID::CLR}, {ID::Q}); - setup_type(ID($ff), {ID::D}, {ID::Q}); - setup_type(ID($dff), {ID::CLK, ID::D}, {ID::Q}); - setup_type(ID($dffe), {ID::CLK, ID::EN, ID::D}, {ID::Q}); - setup_type(ID($dffsr), {ID::CLK, ID::SET, ID::CLR, ID::D}, {ID::Q}); - setup_type(ID($dffsre), {ID::CLK, ID::SET, ID::CLR, ID::D, ID::EN}, {ID::Q}); - setup_type(ID($adff), {ID::CLK, ID::ARST, ID::D}, {ID::Q}); - setup_type(ID($adffe), {ID::CLK, ID::ARST, ID::D, ID::EN}, {ID::Q}); - setup_type(ID($aldff), {ID::CLK, ID::ALOAD, ID::AD, ID::D}, {ID::Q}); - setup_type(ID($aldffe), {ID::CLK, ID::ALOAD, ID::AD, ID::D, ID::EN}, {ID::Q}); - setup_type(ID($sdff), {ID::CLK, ID::SRST, ID::D}, {ID::Q}); - setup_type(ID($sdffe), {ID::CLK, ID::SRST, ID::D, ID::EN}, {ID::Q}); - setup_type(ID($sdffce), {ID::CLK, ID::SRST, ID::D, ID::EN}, {ID::Q}); - setup_type(ID($dlatch), {ID::EN, ID::D}, {ID::Q}); - setup_type(ID($adlatch), {ID::EN, ID::D, ID::ARST}, {ID::Q}); - setup_type(ID($dlatchsr), {ID::EN, ID::SET, ID::CLR, ID::D}, {ID::Q}); + setup_ff_type(ID($sr), {ID::SET, ID::CLR}, {ID::Q}); + setup_ff_type(ID($ff), {ID::D}, {ID::Q}); + setup_ff_type(ID($dff), {ID::CLK, ID::D}, {ID::Q}); + setup_ff_type(ID($dffe), {ID::CLK, ID::EN, ID::D}, {ID::Q}); + setup_ff_type(ID($dffsr), {ID::CLK, ID::SET, ID::CLR, ID::D}, {ID::Q}); + setup_ff_type(ID($dffsre), {ID::CLK, ID::SET, ID::CLR, ID::D, ID::EN}, {ID::Q}); + setup_ff_type(ID($adff), {ID::CLK, ID::ARST, ID::D}, {ID::Q}); + setup_ff_type(ID($adffe), {ID::CLK, ID::ARST, ID::D, ID::EN}, {ID::Q}); + setup_ff_type(ID($aldff), {ID::CLK, ID::ALOAD, ID::AD, ID::D}, {ID::Q}); + setup_ff_type(ID($aldffe), {ID::CLK, ID::ALOAD, ID::AD, ID::D, ID::EN}, {ID::Q}); + setup_ff_type(ID($sdff), {ID::CLK, ID::SRST, ID::D}, {ID::Q}); + setup_ff_type(ID($sdffe), {ID::CLK, ID::SRST, ID::D, ID::EN}, {ID::Q}); + setup_ff_type(ID($sdffce), {ID::CLK, ID::SRST, ID::D, ID::EN}, {ID::Q}); + setup_ff_type(ID($dlatch), {ID::EN, ID::D}, {ID::Q}); + setup_ff_type(ID($adlatch), {ID::EN, ID::D, ID::ARST}, {ID::Q}); + setup_ff_type(ID($dlatchsr), {ID::EN, ID::SET, ID::CLR, ID::D}, {ID::Q}); } void setup_internals_anyinit() { - setup_type(ID($anyinit), {ID::D}, {ID::Q}); + setup_formal_type(ID($anyinit), {ID::D}, {ID::Q}); } void setup_internals_mem() @@ -196,30 +221,30 @@ struct CellTypes { setup_stdcells_eval(); - setup_type(ID($_TBUF_), {ID::A, ID::E}, {ID::Y}, true); + setup_comb_type(ID($_TBUF_), {ID::A, ID::E}, {ID::Y}); } void setup_stdcells_eval() { - setup_type(ID($_BUF_), {ID::A}, {ID::Y}, true); - setup_type(ID($_NOT_), {ID::A}, {ID::Y}, true); - setup_type(ID($_AND_), {ID::A, ID::B}, {ID::Y}, true); - setup_type(ID($_NAND_), {ID::A, ID::B}, {ID::Y}, true); - setup_type(ID($_OR_), {ID::A, ID::B}, {ID::Y}, true); - setup_type(ID($_NOR_), {ID::A, ID::B}, {ID::Y}, true); - setup_type(ID($_XOR_), {ID::A, ID::B}, {ID::Y}, true); - setup_type(ID($_XNOR_), {ID::A, ID::B}, {ID::Y}, true); - setup_type(ID($_ANDNOT_), {ID::A, ID::B}, {ID::Y}, true); - setup_type(ID($_ORNOT_), {ID::A, ID::B}, {ID::Y}, true); - setup_type(ID($_MUX_), {ID::A, ID::B, ID::S}, {ID::Y}, true); - setup_type(ID($_NMUX_), {ID::A, ID::B, ID::S}, {ID::Y}, true); - setup_type(ID($_MUX4_), {ID::A, ID::B, ID::C, ID::D, ID::S, ID::T}, {ID::Y}, true); - setup_type(ID($_MUX8_), {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::S, ID::T, ID::U}, {ID::Y}, true); - setup_type(ID($_MUX16_), {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::I, ID::J, ID::K, ID::L, ID::M, ID::N, ID::O, ID::P, ID::S, ID::T, ID::U, ID::V}, {ID::Y}, true); - setup_type(ID($_AOI3_), {ID::A, ID::B, ID::C}, {ID::Y}, true); - setup_type(ID($_OAI3_), {ID::A, ID::B, ID::C}, {ID::Y}, true); - setup_type(ID($_AOI4_), {ID::A, ID::B, ID::C, ID::D}, {ID::Y}, true); - setup_type(ID($_OAI4_), {ID::A, ID::B, ID::C, ID::D}, {ID::Y}, true); + setup_comb_type(ID($_BUF_), {ID::A}, {ID::Y}); + setup_comb_type(ID($_NOT_), {ID::A}, {ID::Y}); + setup_comb_type(ID($_AND_), {ID::A, ID::B}, {ID::Y}); + setup_comb_type(ID($_NAND_), {ID::A, ID::B}, {ID::Y}); + setup_comb_type(ID($_OR_), {ID::A, ID::B}, {ID::Y}); + setup_comb_type(ID($_NOR_), {ID::A, ID::B}, {ID::Y}); + setup_comb_type(ID($_XOR_), {ID::A, ID::B}, {ID::Y}); + setup_comb_type(ID($_XNOR_), {ID::A, ID::B}, {ID::Y}); + setup_comb_type(ID($_ANDNOT_), {ID::A, ID::B}, {ID::Y}); + setup_comb_type(ID($_ORNOT_), {ID::A, ID::B}, {ID::Y}); + setup_comb_type(ID($_MUX_), {ID::A, ID::B, ID::S}, {ID::Y}); + setup_comb_type(ID($_NMUX_), {ID::A, ID::B, ID::S}, {ID::Y}); + setup_comb_type(ID($_MUX4_), {ID::A, ID::B, ID::C, ID::D, ID::S, ID::T}, {ID::Y}); + setup_comb_type(ID($_MUX8_), {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::S, ID::T, ID::U}, {ID::Y}); + setup_comb_type(ID($_MUX16_), {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::I, ID::J, ID::K, ID::L, ID::M, ID::N, ID::O, ID::P, ID::S, ID::T, ID::U, ID::V}, {ID::Y}); + setup_comb_type(ID($_AOI3_), {ID::A, ID::B, ID::C}, {ID::Y}); + setup_comb_type(ID($_OAI3_), {ID::A, ID::B, ID::C}, {ID::Y}); + setup_comb_type(ID($_AOI4_), {ID::A, ID::B, ID::C, ID::D}, {ID::Y}); + setup_comb_type(ID($_OAI4_), {ID::A, ID::B, ID::C, ID::D}, {ID::Y}); } void setup_stdcells_mem() @@ -228,77 +253,77 @@ struct CellTypes for (auto c1 : list_np) for (auto c2 : list_np) - setup_type(stringf("$_SR_%c%c_", c1, c2), {ID::S, ID::R}, {ID::Q}); + setup_ff_type(stringf("$_SR_%c%c_", c1, c2), {ID::S, ID::R}, {ID::Q}); - setup_type(ID($_FF_), {ID::D}, {ID::Q}); + setup_ff_type(ID($_FF_), {ID::D}, {ID::Q}); for (auto c1 : list_np) - setup_type(stringf("$_DFF_%c_", c1), {ID::C, ID::D}, {ID::Q}); + setup_ff_type(stringf("$_DFF_%c_", c1), {ID::C, ID::D}, {ID::Q}); for (auto c1 : list_np) for (auto c2 : list_np) - setup_type(stringf("$_DFFE_%c%c_", c1, c2), {ID::C, ID::D, ID::E}, {ID::Q}); + setup_ff_type(stringf("$_DFFE_%c%c_", c1, c2), {ID::C, ID::D, ID::E}, {ID::Q}); for (auto c1 : list_np) for (auto c2 : list_np) for (auto c3 : list_01) - setup_type(stringf("$_DFF_%c%c%c_", c1, c2, c3), {ID::C, ID::R, ID::D}, {ID::Q}); + setup_ff_type(stringf("$_DFF_%c%c%c_", c1, c2, c3), {ID::C, ID::R, ID::D}, {ID::Q}); for (auto c1 : list_np) for (auto c2 : list_np) for (auto c3 : list_01) for (auto c4 : list_np) - setup_type(stringf("$_DFFE_%c%c%c%c_", c1, c2, c3, c4), {ID::C, ID::R, ID::D, ID::E}, {ID::Q}); + setup_ff_type(stringf("$_DFFE_%c%c%c%c_", c1, c2, c3, c4), {ID::C, ID::R, ID::D, ID::E}, {ID::Q}); for (auto c1 : list_np) for (auto c2 : list_np) - setup_type(stringf("$_ALDFF_%c%c_", c1, c2), {ID::C, ID::L, ID::AD, ID::D}, {ID::Q}); + setup_ff_type(stringf("$_ALDFF_%c%c_", c1, c2), {ID::C, ID::L, ID::AD, ID::D}, {ID::Q}); for (auto c1 : list_np) for (auto c2 : list_np) for (auto c3 : list_np) - setup_type(stringf("$_ALDFFE_%c%c%c_", c1, c2, c3), {ID::C, ID::L, ID::AD, ID::D, ID::E}, {ID::Q}); + setup_ff_type(stringf("$_ALDFFE_%c%c%c_", c1, c2, c3), {ID::C, ID::L, ID::AD, ID::D, ID::E}, {ID::Q}); for (auto c1 : list_np) for (auto c2 : list_np) for (auto c3 : list_np) - setup_type(stringf("$_DFFSR_%c%c%c_", c1, c2, c3), {ID::C, ID::S, ID::R, ID::D}, {ID::Q}); + setup_ff_type(stringf("$_DFFSR_%c%c%c_", c1, c2, c3), {ID::C, ID::S, ID::R, ID::D}, {ID::Q}); for (auto c1 : list_np) for (auto c2 : list_np) for (auto c3 : list_np) for (auto c4 : list_np) - setup_type(stringf("$_DFFSRE_%c%c%c%c_", c1, c2, c3, c4), {ID::C, ID::S, ID::R, ID::D, ID::E}, {ID::Q}); + setup_ff_type(stringf("$_DFFSRE_%c%c%c%c_", c1, c2, c3, c4), {ID::C, ID::S, ID::R, ID::D, ID::E}, {ID::Q}); for (auto c1 : list_np) for (auto c2 : list_np) for (auto c3 : list_01) - setup_type(stringf("$_SDFF_%c%c%c_", c1, c2, c3), {ID::C, ID::R, ID::D}, {ID::Q}); + setup_ff_type(stringf("$_SDFF_%c%c%c_", c1, c2, c3), {ID::C, ID::R, ID::D}, {ID::Q}); for (auto c1 : list_np) for (auto c2 : list_np) for (auto c3 : list_01) for (auto c4 : list_np) - setup_type(stringf("$_SDFFE_%c%c%c%c_", c1, c2, c3, c4), {ID::C, ID::R, ID::D, ID::E}, {ID::Q}); + setup_ff_type(stringf("$_SDFFE_%c%c%c%c_", c1, c2, c3, c4), {ID::C, ID::R, ID::D, ID::E}, {ID::Q}); for (auto c1 : list_np) for (auto c2 : list_np) for (auto c3 : list_01) for (auto c4 : list_np) - setup_type(stringf("$_SDFFCE_%c%c%c%c_", c1, c2, c3, c4), {ID::C, ID::R, ID::D, ID::E}, {ID::Q}); + setup_ff_type(stringf("$_SDFFCE_%c%c%c%c_", c1, c2, c3, c4), {ID::C, ID::R, ID::D, ID::E}, {ID::Q}); for (auto c1 : list_np) - setup_type(stringf("$_DLATCH_%c_", c1), {ID::E, ID::D}, {ID::Q}); + setup_ff_type(stringf("$_DLATCH_%c_", c1), {ID::E, ID::D}, {ID::Q}); for (auto c1 : list_np) for (auto c2 : list_np) for (auto c3 : list_01) - setup_type(stringf("$_DLATCH_%c%c%c_", c1, c2, c3), {ID::E, ID::R, ID::D}, {ID::Q}); + setup_ff_type(stringf("$_DLATCH_%c%c%c_", c1, c2, c3), {ID::E, ID::R, ID::D}, {ID::Q}); for (auto c1 : list_np) for (auto c2 : list_np) for (auto c3 : list_np) - setup_type(stringf("$_DLATCHSR_%c%c%c_", c1, c2, c3), {ID::E, ID::S, ID::R, ID::D}, {ID::Q}); + setup_ff_type(stringf("$_DLATCHSR_%c%c%c_", c1, c2, c3), {ID::E, ID::S, ID::R, ID::D}, {ID::Q}); } void clear() From 4883c503a882a3168f23cdb50dec289908a54666 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 21 Feb 2025 16:10:51 +1300 Subject: [PATCH 03/10] celltypes: get_cell() helper Add `CellTypes::get_cell()` which takes a 'type' `IdString` and returns the corresponding `CellType` if it is in the `cell_types` dict, otherwise returns `nullptr`. Useful for getting a cell type by name and then checking its attributes. --- kernel/celltypes.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 08773b4eb..441fc1d10 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -331,6 +331,15 @@ struct CellTypes cell_types.clear(); } + const CellType* get_cell(RTLIL::IdString type) const + { + auto it = cell_types.find(type); + if (it == cell_types.end()) + return nullptr; + else + return &(it->second); + } + bool cell_known(RTLIL::IdString type) const { return cell_types.count(type) != 0; From d61391390558eac2c79d45c021bea7b916813ac7 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 21 Feb 2025 16:17:23 +1300 Subject: [PATCH 04/10] select: Add cell type property selector Looks up the cell type for each cell in the design, returning the value of `CellType::is_`. Only works for exact match, and only for internal cells. Also add a simple test checking a small design with an $add cell and an $sdff cell. --- passes/cmds/select.cc | 34 ++++++++++++++++++++++++++++++ tests/select/type_props.ys | 42 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 tests/select/type_props.ys diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc index aec4c964b..dccc99d02 100644 --- a/passes/cmds/select.cc +++ b/passes/cmds/select.cc @@ -141,6 +141,30 @@ static bool match_attr(const dict &attributes, co return match_attr(attributes, match_expr, std::string(), 0); } +static bool match_type_prop(RTLIL::IdString type, const std::string &property) +{ + auto *ct = yosys_celltypes.get_cell(type); + if (ct == nullptr) { + return false; + } else + if (property.compare("evaluable") == 0) { + return ct->is_evaluable; + } else + if (property.compare("combinatorial") == 0) { + return ct->is_combinatorial; + } else + if (property.compare("synthesizable") == 0) { + return ct->is_synthesizable; + } else + if (property.compare("builtin_ff") == 0) { + return ct->is_builtin_ff; + } else + if (property.compare("formal") == 0) { + return ct->is_formal; + } else + log_cmd_error("Unsupported type property '%s'!\n", property.c_str()); +} + static void select_op_neg(RTLIL::Design *design, RTLIL::Selection &lhs) { if (lhs.full_selection) { @@ -891,6 +915,11 @@ static void select_stmt(RTLIL::Design *design, std::string arg, bool disable_emp sel.selected_members[mod->name].insert(cell->name); } } else + if (arg_memb.compare(0, 2, "y:") == 0) { + for (auto cell : mod->cells()) + if (match_type_prop(cell->type, arg_memb.substr(2))) + sel.selected_members[mod->name].insert(cell->name); + } else if (arg_memb.compare(0, 2, "p:") == 0) { for (auto &it : mod->processes) if (match_ids(it.first, arg_memb.substr(2))) @@ -1178,6 +1207,11 @@ struct SelectPass : public Pass { log(" t:@\n"); log(" all cells with a type matching a module in the saved selection \n"); log("\n"); + log(" y:\n"); + log(" all cells with a given type property, possible values are:\n"); + log(" evaluable, combinatorial, synthesizable, builtin_ff, formal\n"); + log(" (currently only internal cells can have type properties)\n"); + log("\n"); log(" p:\n"); log(" all processes with a name matching the given pattern\n"); log("\n"); diff --git a/tests/select/type_props.ys b/tests/select/type_props.ys new file mode 100644 index 000000000..44f181054 --- /dev/null +++ b/tests/select/type_props.ys @@ -0,0 +1,42 @@ +read_rtlil << EOF +module \sm2 + + wire input 1 \clk + wire input 2 \rst + wire width 2 input 3 \a + + wire width 2 \add_Y + + attribute \init 2'00 + wire width 2 output 4 \y + + cell $add \add + parameter \A_SIGNED 0 + parameter \A_WIDTH 2 + parameter \B_SIGNED 0 + parameter \B_WIDTH 2 + parameter \Y_WIDTH 2 + connect \A \y + connect \B \a + connect \Y \add_Y + end + + cell $sdff \sdff + parameter \CLK_POLARITY 1 + parameter \SRST_POLARITY 1 + parameter \SRST_VALUE 2'00 + parameter \WIDTH 2 + connect \CLK \clk + connect \D \add_Y + connect \Q \y + connect \SRST \rst + end +end + +EOF + +select -assert-count 1 y:evaluable +select -assert-count 1 y:combinatorial +select -assert-count 2 y:synthesizable +select -assert-count 1 y:builtin_ff +select -assert-count 0 y:formal From 647ea922f112bc2ed19c10c8084f9aacb58a701f Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 25 Feb 2025 13:40:51 +1300 Subject: [PATCH 05/10] celltypes: Extra type props Now with `is_internal`, `is_metainfo`, and `has_effects`. Each type property has a comment specifying usage/meaning. Type properties (sans `is_internal`) get a default value of false. `CellTypes::setup_*_type()` methods get their own `CellType` struct assignments with named fields being assigned true to improve readability. --- kernel/celltypes.h | 163 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 126 insertions(+), 37 deletions(-) diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 441fc1d10..11203a872 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -28,11 +28,25 @@ struct CellType { RTLIL::IdString type; pool inputs, outputs; - bool is_evaluable; - bool is_combinatorial; - bool is_synthesizable; - bool is_builtin_ff; - bool is_formal; + // Cell is defined in celltypes.h, as opposed to design-specific + bool is_internal; + // Cell can be handled by CellTypes::eval() + bool is_evaluable = false; + // Cell has no state; outputs are determined solely by inputs + bool is_combinatorial = false; + // Cell is able to be fully represented in the synthesizable subset of verilog + bool is_synthesizable = false; + // Cell is built-in memory logic, includes flip-flops and latches, but not complex + // cells like $mem + bool is_builtin_ff = false; + // Cell is non-synthesizable, but used for formal verification + bool is_formal = false; + // Cell is intended for internal Yosys use, containing informational metadata and + // shouldn't be automatically cleaned; currently only used for $scopeinfo + bool is_metainfo = false; + // Non-synthesizable cell with effects that mean it shouldn't be automatically + // cleaned, e.g. $print + bool has_effects = false; }; struct CellTypes @@ -60,30 +74,102 @@ struct CellTypes setup_stdcells_mem(); } - void setup_type(RTLIL::IdString type, const pool &inputs, const pool &outputs, - bool is_evaluable = false, bool is_combinatorial = false, bool is_synthesizable = false, - bool is_builtin_ff = false, bool is_formal = false) + void setup_type(RTLIL::IdString type, const pool &inputs, const pool &outputs) { - CellType ct = {type, inputs, outputs, is_evaluable, is_combinatorial, is_synthesizable, is_builtin_ff, is_formal}; + CellType ct = { + .type = type, + .inputs = inputs, + .outputs = outputs, + .is_internal = false + }; cell_types[ct.type] = ct; } - // Setup combinational cell type which is evaluable and synthesizable - void setup_comb_type(RTLIL::IdString type, const pool &inputs, const pool &outputs) + // Setup internal cell type with no other default properties + void setup_internal_type(RTLIL::IdString type, const pool &inputs, const pool &outputs, + bool is_combinatorial = false) { - setup_type(type, inputs, outputs, true, true, true, false, false); + CellType ct = { + .type = type, + .inputs = inputs, + .outputs = outputs, + .is_internal = true, + .is_combinatorial = is_combinatorial, + }; + cell_types[ct.type] = ct; + } + + // Setup combinatorial cell type which is synthesizable and evaluable (by default) + void setup_comb_type(RTLIL::IdString type, const pool &inputs, const pool &outputs, + bool is_evaluable = true) + { + CellType ct = { + .type = type, + .inputs = inputs, + .outputs = outputs, + .is_internal = true, + .is_evaluable = is_evaluable, + .is_combinatorial = true, + .is_synthesizable = true, + }; + cell_types[ct.type] = ct; } // Setup builtin ff cell type which is synthesizable void setup_ff_type(RTLIL::IdString type, const pool &inputs, const pool &outputs) { - setup_type(type, inputs, outputs, false, false, true, true, false); + CellType ct = { + .type = type, + .inputs = inputs, + .outputs = outputs, + .is_internal = true, + .is_synthesizable = true, + .is_builtin_ff = true, + }; + cell_types[ct.type] = ct; } - // Setup formal cell type which may be evaluable - void setup_formal_type(RTLIL::IdString type, const pool &inputs, const pool &outputs, bool is_evaluable = false) + // Setup formal cell type which may be combinatorial, and may have effects + void setup_formal_type(RTLIL::IdString type, const pool &inputs, const pool &outputs, + bool is_combinatorial = false) { - setup_type(type, inputs, outputs, is_evaluable, false, false, false, true); + CellType ct = { + .type = type, + .inputs = inputs, + .outputs = outputs, + .is_internal = true, + .is_combinatorial = is_combinatorial, + .is_formal = true, + }; + cell_types[ct.type] = ct; + } + + // Setup cell type which has effects, and may be formal + void setup_effects_type(RTLIL::IdString type, const pool &inputs, const pool &outputs, + bool is_formal = false) + { + CellType ct = { + .type = type, + .inputs = inputs, + .outputs = outputs, + .is_internal = true, + .is_formal = is_formal, + .has_effects = true, + }; + cell_types[ct.type] = ct; + } + + // Setup meta-info cell type + void setup_metainfo_type(RTLIL::IdString type, const pool &inputs, const pool &outputs) + { + CellType ct = { + .type = type, + .inputs = inputs, + .outputs = outputs, + .is_internal = true, + .is_metainfo = true, + }; + cell_types[ct.type] = ct; } void setup_module(RTLIL::Module *module) @@ -109,9 +195,10 @@ struct CellTypes { setup_internals_eval(); - setup_comb_type(ID($tribuf), {ID::A, ID::EN}, {ID::Y}); + // synthesizable + setup_comb_type(ID($tribuf), {ID::A, ID::EN}, {ID::Y}, false); - // evaluable formal + // combinatorial formal setup_formal_type(ID($assert), {ID::A, ID::EN}, pool(), true); setup_formal_type(ID($assume), {ID::A, ID::EN}, pool(), true); setup_formal_type(ID($live), {ID::A, ID::EN}, pool(), true); @@ -124,22 +211,24 @@ struct CellTypes setup_formal_type(ID($allseq), pool(), {ID::Y}, true); setup_formal_type(ID($equiv), {ID::A, ID::B}, {ID::Y}, true); - // evaluable non-formal - setup_type(ID($specify2), {ID::EN, ID::SRC, ID::DST}, pool(), true); - setup_type(ID($specify3), {ID::EN, ID::SRC, ID::DST, ID::DAT}, pool(), true); - setup_type(ID($specrule), {ID::EN_SRC, ID::EN_DST, ID::SRC, ID::DST}, pool(), true); - setup_type(ID($print), {ID::EN, ID::ARGS, ID::TRG}, pool()); + // combinatorial non-synthesizable + setup_internal_type(ID($specify2), {ID::EN, ID::SRC, ID::DST}, pool(), true); + setup_internal_type(ID($specify3), {ID::EN, ID::SRC, ID::DST, ID::DAT}, pool(), true); + setup_internal_type(ID($specrule), {ID::EN_SRC, ID::EN_DST, ID::SRC, ID::DST}, pool(), true); - // non-evaluable formal - setup_formal_type(ID($check), {ID::A, ID::EN, ID::ARGS, ID::TRG}, pool()); + // non-combinatorial formal setup_formal_type(ID($set_tag), {ID::A, ID::SET, ID::CLR}, {ID::Y}); setup_formal_type(ID($get_tag), {ID::A}, {ID::Y}); setup_formal_type(ID($overwrite_tag), {ID::A, ID::SET, ID::CLR}, pool()); setup_formal_type(ID($original_tag), {ID::A}, {ID::Y}); setup_formal_type(ID($future_ff), {ID::A}, {ID::Y}); - // non-evaluable non-formal - setup_type(ID($scopeinfo), {}, {}); + // has effects + setup_effects_type(ID($print), {ID::EN, ID::ARGS, ID::TRG}, pool()); + setup_effects_type(ID($check), {ID::A, ID::EN, ID::ARGS, ID::TRG}, pool(), true); + + // meta-info + setup_metainfo_type(ID($scopeinfo), {}, {}); } void setup_internals_eval() @@ -205,23 +294,23 @@ struct CellTypes { setup_internals_ff(); - setup_type(ID($memrd), {ID::CLK, ID::EN, ID::ADDR}, {ID::DATA}); - setup_type(ID($memrd_v2), {ID::CLK, ID::EN, ID::ARST, ID::SRST, ID::ADDR}, {ID::DATA}); - setup_type(ID($memwr), {ID::CLK, ID::EN, ID::ADDR, ID::DATA}, pool()); - setup_type(ID($memwr_v2), {ID::CLK, ID::EN, ID::ADDR, ID::DATA}, pool()); - setup_type(ID($meminit), {ID::ADDR, ID::DATA}, pool()); - setup_type(ID($meminit_v2), {ID::ADDR, ID::DATA, ID::EN}, pool()); - setup_type(ID($mem), {ID::RD_CLK, ID::RD_EN, ID::RD_ADDR, ID::WR_CLK, ID::WR_EN, ID::WR_ADDR, ID::WR_DATA}, {ID::RD_DATA}); - setup_type(ID($mem_v2), {ID::RD_CLK, ID::RD_EN, ID::RD_ARST, ID::RD_SRST, ID::RD_ADDR, ID::WR_CLK, ID::WR_EN, ID::WR_ADDR, ID::WR_DATA}, {ID::RD_DATA}); + setup_internal_type(ID($memrd), {ID::CLK, ID::EN, ID::ADDR}, {ID::DATA}); + setup_internal_type(ID($memrd_v2), {ID::CLK, ID::EN, ID::ARST, ID::SRST, ID::ADDR}, {ID::DATA}); + setup_internal_type(ID($memwr), {ID::CLK, ID::EN, ID::ADDR, ID::DATA}, pool()); + setup_internal_type(ID($memwr_v2), {ID::CLK, ID::EN, ID::ADDR, ID::DATA}, pool()); + setup_internal_type(ID($meminit), {ID::ADDR, ID::DATA}, pool()); + setup_internal_type(ID($meminit_v2), {ID::ADDR, ID::DATA, ID::EN}, pool()); + setup_internal_type(ID($mem), {ID::RD_CLK, ID::RD_EN, ID::RD_ADDR, ID::WR_CLK, ID::WR_EN, ID::WR_ADDR, ID::WR_DATA}, {ID::RD_DATA}); + setup_internal_type(ID($mem_v2), {ID::RD_CLK, ID::RD_EN, ID::RD_ARST, ID::RD_SRST, ID::RD_ADDR, ID::WR_CLK, ID::WR_EN, ID::WR_ADDR, ID::WR_DATA}, {ID::RD_DATA}); - setup_type(ID($fsm), {ID::CLK, ID::ARST, ID::CTRL_IN}, {ID::CTRL_OUT}); + setup_internal_type(ID($fsm), {ID::CLK, ID::ARST, ID::CTRL_IN}, {ID::CTRL_OUT}); } void setup_stdcells() { setup_stdcells_eval(); - setup_comb_type(ID($_TBUF_), {ID::A, ID::E}, {ID::Y}); + setup_comb_type(ID($_TBUF_), {ID::A, ID::E}, {ID::Y}, false); } void setup_stdcells_eval() From 425c7fe4cf9955e6069733f608c73150b5dade79 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 25 Feb 2025 13:41:14 +1300 Subject: [PATCH 06/10] select: New type props --- passes/cmds/select.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc index dccc99d02..2915552f9 100644 --- a/passes/cmds/select.cc +++ b/passes/cmds/select.cc @@ -147,6 +147,9 @@ static bool match_type_prop(RTLIL::IdString type, const std::string &property) if (ct == nullptr) { return false; } else + if (property.compare("internal") == 0) { + return ct->is_internal; + } else if (property.compare("evaluable") == 0) { return ct->is_evaluable; } else @@ -161,6 +164,12 @@ static bool match_type_prop(RTLIL::IdString type, const std::string &property) } else if (property.compare("formal") == 0) { return ct->is_formal; + } else + if (property.compare("metainfo") == 0) { + return ct->is_metainfo; + } else + if (property.compare("effects") == 0) { + return ct->has_effects; } else log_cmd_error("Unsupported type property '%s'!\n", property.c_str()); } From d1f6d67d857636cb22438c424ba5d12058571285 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 25 Feb 2025 13:42:36 +1300 Subject: [PATCH 07/10] amend! celltypes: Extra type props celltypes: Extra type props Now with `is_internal`, `is_metainfo`, and `has_effects`. Each type property has a comment specifying usage/meaning. Type properties (sans `is_internal`) get a default value of false. `CellTypes::setup_*_type()` methods get their own `CellType` struct assignments with named fields being assigned true to improve readability. Also remove `is_evaluable` from cell types that aren't actually `eval`-able, instead using `is_combinatorial` which afaict is what the flag was being used as a proxy for. From 82ae46dfeb1d5e4cba9d8b5cec223f8b82859b3f Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 1 Mar 2025 10:52:29 +1300 Subject: [PATCH 08/10] celltypes: Add help -celltypes Like `help -cells` but instead of printing the cell's ports, prints its flags. --- kernel/register.cc | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/kernel/register.cc b/kernel/register.cc index 11cf5b0e4..dbdcfc408 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -1074,6 +1074,36 @@ struct HelpPass : public Pass { log("\n"); return; } + else if (args[1] == "-celltypes") { + log("\n"); + for (auto &it : cell_help_messages.cell_help) { + SimHelper help_cell = it.second; + auto *ct = yosys_celltypes.get_cell(it.first); + char ct_flags[8] = ""; + if (ct != nullptr && ct->is_internal) { + ct_flags[0] = ct->is_evaluable ? 'E' : '-'; + ct_flags[1] = ct->is_combinatorial ? 'C' : '-'; + ct_flags[2] = ct->is_synthesizable ? 'S' : '-'; + ct_flags[3] = ct->is_builtin_ff ? 'M' : '-'; + ct_flags[4] = ct->is_formal ? 'F' : '-'; + ct_flags[5] = ct->is_metainfo ? 'I' : '-'; + ct_flags[6] = ct->has_effects ? 'X' : '-'; + ct_flags[7] = 0; + } + log(" %-15s %s\n", help_cell.name.c_str(), ct_flags); + } + log("\n"); + log("Legend:\n"); + log(" E = evaluable\n"); + log(" C = combinatorial\n"); + log(" S = synthesizable\n"); + log(" M = builtin_ff\n"); + log(" F = formal\n"); + log(" I = metainfo\n"); + log(" X = effects\n"); + log("\n"); + return; + } // this option is undocumented as it is for internal use only else if (args[1] == "-write-rst-command-reference-manual") { for (auto &it : pass_register) { From 91179261575ded57b71d1129b7e6e6fe2322dcf8 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 1 Mar 2025 11:23:13 +1300 Subject: [PATCH 09/10] celltypes: Reword synthesizable comment Don't mention verilog. --- kernel/celltypes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 11203a872..49f63272e 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -34,7 +34,7 @@ struct CellType bool is_evaluable = false; // Cell has no state; outputs are determined solely by inputs bool is_combinatorial = false; - // Cell is able to be fully represented in the synthesizable subset of verilog + // Cell is able to be synthesized bool is_synthesizable = false; // Cell is built-in memory logic, includes flip-flops and latches, but not complex // cells like $mem From e7cfb0381c226e3e78106575ca779e1d56948c5a Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 1 Mar 2025 11:24:25 +1300 Subject: [PATCH 10/10] Celltypes: Revert c++20 feature Turns out using designated initializers is c++20, so not available while we are still c++17 friendly. --- kernel/celltypes.h | 70 +++++++++------------------------------------- 1 file changed, 13 insertions(+), 57 deletions(-) diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 49f63272e..13b1beffd 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -76,25 +76,21 @@ struct CellTypes void setup_type(RTLIL::IdString type, const pool &inputs, const pool &outputs) { - CellType ct = { - .type = type, - .inputs = inputs, - .outputs = outputs, - .is_internal = false - }; + CellType ct = { type, inputs, outputs, false }; cell_types[ct.type] = ct; } // Setup internal cell type with no other default properties void setup_internal_type(RTLIL::IdString type, const pool &inputs, const pool &outputs, - bool is_combinatorial = false) + bool is_combinatorial = false, bool is_evaluable = false, + bool is_synthesizable = false, bool is_builtin_ff = false, bool is_formal = false, + bool is_metainfo = false, bool has_effects = false) { CellType ct = { - .type = type, - .inputs = inputs, - .outputs = outputs, - .is_internal = true, - .is_combinatorial = is_combinatorial, + type, inputs, outputs, true, + is_evaluable, is_combinatorial, + is_synthesizable, is_builtin_ff, is_formal, + is_metainfo, has_effects, }; cell_types[ct.type] = ct; } @@ -103,73 +99,33 @@ struct CellTypes void setup_comb_type(RTLIL::IdString type, const pool &inputs, const pool &outputs, bool is_evaluable = true) { - CellType ct = { - .type = type, - .inputs = inputs, - .outputs = outputs, - .is_internal = true, - .is_evaluable = is_evaluable, - .is_combinatorial = true, - .is_synthesizable = true, - }; - cell_types[ct.type] = ct; + setup_internal_type(type, inputs, outputs, true, is_evaluable, true); } // Setup builtin ff cell type which is synthesizable void setup_ff_type(RTLIL::IdString type, const pool &inputs, const pool &outputs) { - CellType ct = { - .type = type, - .inputs = inputs, - .outputs = outputs, - .is_internal = true, - .is_synthesizable = true, - .is_builtin_ff = true, - }; - cell_types[ct.type] = ct; + setup_internal_type(type, inputs, outputs, false, false, true, true); } // Setup formal cell type which may be combinatorial, and may have effects void setup_formal_type(RTLIL::IdString type, const pool &inputs, const pool &outputs, bool is_combinatorial = false) { - CellType ct = { - .type = type, - .inputs = inputs, - .outputs = outputs, - .is_internal = true, - .is_combinatorial = is_combinatorial, - .is_formal = true, - }; - cell_types[ct.type] = ct; + setup_internal_type(type, inputs, outputs, is_combinatorial, false, false, false, true); } // Setup cell type which has effects, and may be formal void setup_effects_type(RTLIL::IdString type, const pool &inputs, const pool &outputs, bool is_formal = false) { - CellType ct = { - .type = type, - .inputs = inputs, - .outputs = outputs, - .is_internal = true, - .is_formal = is_formal, - .has_effects = true, - }; - cell_types[ct.type] = ct; + setup_internal_type(type, inputs, outputs, false, false, false, false, is_formal, false, true); } // Setup meta-info cell type void setup_metainfo_type(RTLIL::IdString type, const pool &inputs, const pool &outputs) { - CellType ct = { - .type = type, - .inputs = inputs, - .outputs = outputs, - .is_internal = true, - .is_metainfo = true, - }; - cell_types[ct.type] = ct; + setup_internal_type(type, inputs, outputs, false, false, false, false, false, true); } void setup_module(RTLIL::Module *module)