From 1a1d9494dac313b8399364352c5ee3aea8baf730 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 27 Jul 2026 22:06:22 +0200 Subject: [PATCH 1/5] dfflibmap: check formal verilog test actually maps all flops --- tests/techmap/dfflibmap_proc_formal.ys | 31 +++++++++++++++++--------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/tests/techmap/dfflibmap_proc_formal.ys b/tests/techmap/dfflibmap_proc_formal.ys index 88cb97cdb..851238474 100644 --- a/tests/techmap/dfflibmap_proc_formal.ys +++ b/tests/techmap/dfflibmap_proc_formal.ys @@ -44,10 +44,16 @@ EOT proc opt -read_liberty dfflibmap_dffsr_s.lib - copy top top_unmapped +design -save start + +################################################################## + +design -load start +logger -expect log " mapped 4" 1 dfflibmap -liberty dfflibmap_dffsr_s.lib top +logger -check-expected +read_liberty dfflibmap_dffsr_s.lib clk2fflogic flatten @@ -59,10 +65,11 @@ sat -verify -prove-asserts -set-init-undef -show-public -seq 3 miter ################################################################## -delete top miter - -copy top_unmapped top +design -load start +logger -expect log " mapped 4" 1 dfflibmap -liberty dfflibmap_dffsr_r.lib top +logger -check-expected +read_liberty dfflibmap_dffsr_r.lib clk2fflogic flatten @@ -73,10 +80,11 @@ sat -verify -prove-asserts -set-init-undef -show-public -seq 3 miter ################################################################## -delete top miter - -copy top_unmapped top +design -load start +logger -expect log " mapped 4" 1 dfflibmap -liberty dfflibmap_dffsr_mixedpol.lib top +logger -check-expected +read_liberty dfflibmap_dffsr_mixedpol.lib clk2fflogic flatten @@ -87,10 +95,11 @@ sat -verify -prove-asserts -set-init-undef -show-public -seq 3 miter ################################################################## -delete top miter - -copy top_unmapped top +design -load start +logger -expect log " mapped 4" 1 dfflibmap -liberty dfflibmap_dffsr_not_next.lib top +logger -check-expected +read_liberty dfflibmap_dffsr_not_next.lib clk2fflogic flatten From c50290fdab49f19c59cfbe15ba37b9782d6a71e4 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 27 Jul 2026 22:08:39 +0200 Subject: [PATCH 2/5] dfflibmap: fix formal verilog test so that it actually maps all flops --- tests/techmap/dfflibmap_proc_formal.ys | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/techmap/dfflibmap_proc_formal.ys b/tests/techmap/dfflibmap_proc_formal.ys index 851238474..c687ff507 100644 --- a/tests/techmap/dfflibmap_proc_formal.ys +++ b/tests/techmap/dfflibmap_proc_formal.ys @@ -44,6 +44,7 @@ EOT proc opt +techmap copy top top_unmapped design -save start From db2b3a22e953132f3049cca0f8ba8fd5ba92a55d Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 27 Jul 2026 22:09:57 +0200 Subject: [PATCH 3/5] liberty: remove optimization to simplify control flow, fixing polarities in set&reset behavior modeling --- frontends/liberty/liberty.cc | 46 ------------------------------------ 1 file changed, 46 deletions(-) diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc index 96db2f640..262105bd0 100644 --- a/frontends/liberty/liberty.cc +++ b/frontends/liberty/liberty.cc @@ -237,29 +237,6 @@ static void create_ff(RTLIL::Module *module, const LibertyAst *node) if (clk_sig.size() == 0 || data_sig.size() == 0) log_error("FF cell %s has no next_state and/or clocked_on attribute.\n", name); - for (bool rerun_invert_rollback = true; rerun_invert_rollback;) - { - rerun_invert_rollback = false; - - for (auto &it : module->cells_) { - if (it.second->type == ID($_NOT_) && it.second->getPort(ID::Y) == clk_sig) { - clk_sig = it.second->getPort(ID::A); - clk_polarity = !clk_polarity; - rerun_invert_rollback = true; - } - if (it.second->type == ID($_NOT_) && it.second->getPort(ID::Y) == clear_sig) { - clear_sig = it.second->getPort(ID::A); - clear_polarity = !clear_polarity; - rerun_invert_rollback = true; - } - if (it.second->type == ID($_NOT_) && it.second->getPort(ID::Y) == preset_sig) { - preset_sig = it.second->getPort(ID::A); - preset_polarity = !preset_polarity; - rerun_invert_rollback = true; - } - } - } - for (auto& [out_sig, cp_var, neg] : {tuple{iq_sig, clear_preset_var1, false}, {iqn_sig, clear_preset_var2, true}}) { SigSpec q_sig = out_sig; if (neg) { @@ -346,29 +323,6 @@ static bool create_latch(RTLIL::Module *module, const LibertyAst *node, bool fla return false; } - for (bool rerun_invert_rollback = true; rerun_invert_rollback;) - { - rerun_invert_rollback = false; - - for (auto &it : module->cells_) { - if (it.second->type == ID($_NOT_) && it.second->getPort(ID::Y) == enable_sig) { - enable_sig = it.second->getPort(ID::A); - enable_polarity = !enable_polarity; - rerun_invert_rollback = true; - } - if (it.second->type == ID($_NOT_) && it.second->getPort(ID::Y) == clear_sig) { - clear_sig = it.second->getPort(ID::A); - clear_polarity = !clear_polarity; - rerun_invert_rollback = true; - } - if (it.second->type == ID($_NOT_) && it.second->getPort(ID::Y) == preset_sig) { - preset_sig = it.second->getPort(ID::A); - preset_polarity = !preset_polarity; - rerun_invert_rollback = true; - } - } - } - RTLIL::Cell *cell = module->addCell(NEW_ID, ID($_NOT_)); cell->setPort(ID::A, iq_sig); cell->setPort(ID::Y, iqn_sig); From 82914a02045e6cf549cb67aa1cd9a102e615de12 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 27 Jul 2026 22:24:28 +0200 Subject: [PATCH 4/5] dfflibmap: error on wide registers in design --- passes/techmap/dfflibmap.cc | 6 ++++++ tests/techmap/dfflibmap_wide.ys | 5 +++++ 2 files changed, 11 insertions(+) create mode 100644 tests/techmap/dfflibmap_wide.ys diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc index b2caae460..e6aa664f4 100644 --- a/passes/techmap/dfflibmap.cc +++ b/passes/techmap/dfflibmap.cc @@ -20,6 +20,7 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" #include "kernel/gzip.h" +#include "kernel/newcelltypes.h" #include "libparse.h" #include #include @@ -503,6 +504,11 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module) std::vector cell_list; for (auto cell : module->cells()) { + auto cats = StaticCellTypes::categories; + if (cats.is_ff(cell->type) && !cats.is_stdcell(cell->type)) + log_error("Wide register cell type %s is not supported.\n" + "Convert netlist to gate-level first.\n", cell->type); + if (design->selected(module, cell) && cell_mappings.count(cell->type) > 0) cell_list.push_back(cell); if (cell->type == ID($_NOT_)) diff --git a/tests/techmap/dfflibmap_wide.ys b/tests/techmap/dfflibmap_wide.ys new file mode 100644 index 000000000..b3b50ae14 --- /dev/null +++ b/tests/techmap/dfflibmap_wide.ys @@ -0,0 +1,5 @@ +read_verilog ../sim/dff.v +proc +logger -expect error "not supported" 1 +dfflibmap -liberty dfflibmap.lib +logger -check-expected \ No newline at end of file From ef69127001815baa0528dec3d73371cceee23a8e Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 28 Jul 2026 16:39:08 +0200 Subject: [PATCH 5/5] liberty: refactor out constant bools --- frontends/liberty/liberty.cc | 71 ++++++------------------------------ 1 file changed, 12 insertions(+), 59 deletions(-) diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc index 262105bd0..1ecd51cd8 100644 --- a/frontends/liberty/liberty.cc +++ b/frontends/liberty/liberty.cc @@ -210,7 +210,6 @@ static void create_ff(RTLIL::Module *module, const LibertyAst *node) { auto [iq_sig, iqn_sig] = find_latch_ff_wires(module, node); RTLIL::SigSpec clk_sig, data_sig, clear_sig, preset_sig; - bool clk_polarity = true, clear_polarity = true, preset_polarity = true; const std::string name = module->name.unescape(); std::optional clear_preset_var1; @@ -250,21 +249,21 @@ static void create_ff(RTLIL::Module *module, const LibertyAst *node) cell->setPort(ID::C, clk_sig); if (clear_sig.size() == 0 && preset_sig.size() == 0) { - cell->type = stringf("$_DFF_%c_", clk_polarity ? 'P' : 'N'); + cell->type = stringf("$_DFF_P_"); } if (clear_sig.size() == 1 && preset_sig.size() == 0) { - cell->type = stringf("$_DFF_%c%c0_", clk_polarity ? 'P' : 'N', clear_polarity ? 'P' : 'N'); + cell->type = stringf("$_DFF_PP0_"); cell->setPort(ID::R, clear_sig); } if (clear_sig.size() == 0 && preset_sig.size() == 1) { - cell->type = stringf("$_DFF_%c%c1_", clk_polarity ? 'P' : 'N', preset_polarity ? 'P' : 'N'); + cell->type = stringf("$_DFF_PP1_"); cell->setPort(ID::R, preset_sig); } if (clear_sig.size() == 1 && preset_sig.size() == 1) { - cell->type = stringf("$_DFFSR_%c%c%c_", clk_polarity ? 'P' : 'N', preset_polarity ? 'P' : 'N', clear_polarity ? 'P' : 'N'); + cell->type = stringf("$_DFFSR_PPP_"); SigBit s_sig = preset_sig; SigBit r_sig = clear_sig; @@ -301,7 +300,6 @@ static bool create_latch(RTLIL::Module *module, const LibertyAst *node, bool fla { auto [iq_sig, iqn_sig] = find_latch_ff_wires(module, node); RTLIL::SigSpec enable_sig, data_sig, clear_sig, preset_sig; - bool enable_polarity = true, clear_polarity = true, preset_polarity = true; for (auto child : node->children) { if (child->id == "enable") @@ -327,63 +325,18 @@ static bool create_latch(RTLIL::Module *module, const LibertyAst *node, bool fla cell->setPort(ID::A, iq_sig); cell->setPort(ID::Y, iqn_sig); - if (clear_sig.size() == 1) - { - RTLIL::SigSpec clear_negative = clear_sig; - RTLIL::SigSpec clear_enable = clear_sig; - - if (clear_polarity == true || clear_polarity != enable_polarity) - { - RTLIL::Cell *inv = module->addCell(NEW_ID, ID($_NOT_)); - inv->setPort(ID::A, clear_sig); - inv->setPort(ID::Y, module->addWire(NEW_ID)); - - if (clear_polarity == true) - clear_negative = inv->getPort(ID::Y); - if (clear_polarity != enable_polarity) - clear_enable = inv->getPort(ID::Y); - } - - RTLIL::Cell *data_gate = module->addCell(NEW_ID, ID($_AND_)); - data_gate->setPort(ID::A, data_sig); - data_gate->setPort(ID::B, clear_negative); - data_gate->setPort(ID::Y, data_sig = module->addWire(NEW_ID)); - - RTLIL::Cell *enable_gate = module->addCell(NEW_ID, enable_polarity ? ID($_OR_) : ID($_AND_)); - enable_gate->setPort(ID::A, enable_sig); - enable_gate->setPort(ID::B, clear_enable); - enable_gate->setPort(ID::Y, enable_sig = module->addWire(NEW_ID)); + if (clear_sig.size() == 1) { + RTLIL::SigSpec clear_negative = module->NotGate(NEW_ID, clear_sig); + data_sig = module->AndGate(NEW_ID, data_sig, clear_negative); + enable_sig = module->OrGate(NEW_ID, enable_sig, clear_sig); } - if (preset_sig.size() == 1) - { - RTLIL::SigSpec preset_positive = preset_sig; - RTLIL::SigSpec preset_enable = preset_sig; - - if (preset_polarity == false || preset_polarity != enable_polarity) - { - RTLIL::Cell *inv = module->addCell(NEW_ID, ID($_NOT_)); - inv->setPort(ID::A, preset_sig); - inv->setPort(ID::Y, module->addWire(NEW_ID)); - - if (preset_polarity == false) - preset_positive = inv->getPort(ID::Y); - if (preset_polarity != enable_polarity) - preset_enable = inv->getPort(ID::Y); - } - - RTLIL::Cell *data_gate = module->addCell(NEW_ID, ID($_OR_)); - data_gate->setPort(ID::A, data_sig); - data_gate->setPort(ID::B, preset_positive); - data_gate->setPort(ID::Y, data_sig = module->addWire(NEW_ID)); - - RTLIL::Cell *enable_gate = module->addCell(NEW_ID, enable_polarity ? ID($_OR_) : ID($_AND_)); - enable_gate->setPort(ID::A, enable_sig); - enable_gate->setPort(ID::B, preset_enable); - enable_gate->setPort(ID::Y, enable_sig = module->addWire(NEW_ID)); + if (preset_sig.size() == 1) { + data_sig = module->OrGate(NEW_ID, data_sig, preset_sig); + enable_sig = module->OrGate(NEW_ID, enable_sig, preset_sig); } - cell = module->addCell(NEW_ID, stringf("$_DLATCH_%c_", enable_polarity ? 'P' : 'N')); + cell = module->addCell(NEW_ID, stringf("$_DLATCH_P_")); cell->setPort(ID::D, data_sig); cell->setPort(ID::Q, iq_sig); cell->setPort(ID::E, enable_sig);