From 45880ea7f24b090050b30136bb97a53ccb2fe34f Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 14 Nov 2024 20:37:59 +0100 Subject: [PATCH 1/8] clockgate: add -liberty --- passes/techmap/clockgate.cc | 180 +++++++++++++++++++++++++++++++++++- 1 file changed, 177 insertions(+), 3 deletions(-) diff --git a/passes/techmap/clockgate.cc b/passes/techmap/clockgate.cc index bf53b02bb..373440926 100644 --- a/passes/techmap/clockgate.cc +++ b/passes/techmap/clockgate.cc @@ -1,5 +1,6 @@ #include "kernel/yosys.h" #include "kernel/ff.h" +#include "libparse.h" #include USING_YOSYS_NAMESPACE @@ -10,6 +11,7 @@ struct ClockGateCell { IdString ce_pin; IdString clk_in_pin; IdString clk_out_pin; + std::vector tie_lo_pins; }; ClockGateCell icg_from_arg(std::string& name, std::string& str) { @@ -37,6 +39,161 @@ ClockGateCell icg_from_arg(std::string& name, std::string& str) { return c; } +static std::pair, std::optional> + find_icgs(std::string filename) { + std::ifstream f; + f.open(filename.c_str()); + if (f.fail()) + log_cmd_error("Can't open liberty file `%s': %s\n", filename.c_str(), strerror(errno)); + LibertyParser libparser(f); + f.close(); + auto ast = libparser.ast; + + // We will pick the most suitable ICG absed on tie_lo count and area + struct ICGRankable { + ClockGateCell icg; + double area; + }; + std::optional best_pos; + std::optional best_neg; + + if (ast->id != "library") + log_error("Format error in liberty file.\n"); + + // This is a lot of boilerplate, isn't it? + for (auto cell : ast->children) + { + if (cell->id != "cell" || cell->args.size() != 1) + continue; + + const LibertyAst *dn = cell->find("dont_use"); + if (dn != nullptr && dn->value == "true") + continue; + + // TODO Should we have user-specified dont_use_cells here? + + const LibertyAst *icg_kind_ast = cell->find("clock_gating_integrated_cell"); + if (icg_kind_ast == nullptr) + continue; + + auto cell_name = cell->args[0]; + auto icg_kind = icg_kind_ast->value; + std::vector kind_tags; + std::stringstream ss(icg_kind); + std::string tag; + while (std::getline(ss, tag, '_')) { + kind_tags.push_back(tag); + } + if ((kind_tags.size() < 2) || (kind_tags.size() > 4)) + log_error("Malformed liberty file - invalid clock_gating_integrated_cell value %s in cell %s\n", + icg_kind.c_str(), cell_name.c_str()); + auto internal = kind_tags[0]; + if (internal != "latch") { + // TODO Is this expected behavior? + log_warning("Skipping ICG cell %s - not latch-based\n", cell_name.c_str()); + continue; + } + auto clk_pol_tag = kind_tags[1]; + bool clk_pol; + if (clk_pol_tag == "posedge") { + clk_pol = true; + } else if (clk_pol_tag == "negedge") { + clk_pol = false; + } else { + log_error("Malformed liberty file - invalid clock_gating_integrated_cell value %s in cell %s\n", + icg_kind.c_str(), cell_name.c_str()); + continue; + } + log_debug("maybe valid icg: %s\n", cell_name.c_str()); + ClockGateCell icg_interface; + icg_interface.name = RTLIL::escape_id(cell_name); + + for (auto pin : cell->children) { + if (pin->id != "pin" || pin->args.size() != 1) + continue; + + log("Check pin %s\n", pin->args[0].c_str()); + if (auto clk = pin->find("clock_gate_clock_pin")) { + if (!icg_interface.clk_in_pin.empty()) + log_error("Malformed liberty file - multiple clock_gate_clock_pin in cell %s\n", + cell_name.c_str()); + else + icg_interface.clk_in_pin = RTLIL::escape_id(pin->args[0]); + } else if (auto gclk = pin->find("clock_gate_out_pin")) { + if (!icg_interface.clk_out_pin.empty()) + log_error("Malformed liberty file - multiple clock_gate_out_pin in cell %s\n", + cell_name.c_str()); + else + icg_interface.clk_out_pin = RTLIL::escape_id(pin->args[0]); + } else if (auto en = pin->find("clock_gate_enable_pin")) { + if (!icg_interface.ce_pin.empty()) + log_error("Malformed liberty file - multiple clock_gate_enable_pin in cell %s\n", + cell_name.c_str()); + else + icg_interface.ce_pin = RTLIL::escape_id(pin->args[0]); + } else if (auto se = pin->find("clock_gate_test_pin")) { + icg_interface.tie_lo_pins.push_back(RTLIL::escape_id(pin->args[0])); + } else { + const LibertyAst *dir = pin->find("direction"); + if (dir->value == "internal") + continue; + + log_error("Malformed liberty file - extra pin %s in cell %s\n", + pin->args[0].c_str(), cell_name.c_str()); + } + } + + if (icg_interface.clk_in_pin.empty()) + log_error("Malformed liberty file - missing clock_gate_clock_pin in cell %s", + cell_name.c_str()); + if (icg_interface.clk_out_pin.empty()) + log_error("Malformed liberty file - missing clock_gate_out_pin in cell %s", + cell_name.c_str()); + if (icg_interface.ce_pin.empty()) + log_error("Malformed liberty file - missing clock_gate_enable_pin in cell %s", + cell_name.c_str()); + + double area = 0; + const LibertyAst *ar = cell->find("area"); + if (ar != nullptr && !ar->value.empty()) + area = atof(ar->value.c_str()); + + std::optional& icg_to_beat = clk_pol ? best_pos : best_neg; + + bool winning = false; + if (icg_to_beat) { + log_debug("ties: %zu ? %zu\n", icg_to_beat->icg.tie_lo_pins.size(), + icg_interface.tie_lo_pins.size()); + log_debug("area: %f ? %f\n", icg_to_beat->area, area); + if (icg_to_beat->icg.tie_lo_pins.size() != icg_interface.tie_lo_pins.size()) + winning = icg_to_beat->icg.tie_lo_pins.size() > icg_interface.tie_lo_pins.size(); + else + winning = icg_to_beat->area > area; + if (winning) + log_debug("%s beats %s\n", icg_interface.name.c_str(), icg_to_beat->icg.name.c_str()); + } else { + log_debug("%s is the first of its polarity\n", icg_interface.name.c_str()); + winning = true; + } + if (winning) { + ICGRankable new_icg {icg_interface, area}; + icg_to_beat.emplace(new_icg); + } + } + + std::optional pos; + std::optional neg; + if (best_pos) { + log("Selected rising edge ICG %s\n", best_pos->icg.name.c_str()); + pos.emplace(best_pos->icg); + } + if (best_neg) { + log("Selected falling edge ICG %s\n", best_neg->icg.name.c_str()); + neg.emplace(best_neg->icg); + } + return std::make_pair(pos, neg); +} + struct ClockgatePass : public Pass { ClockgatePass() : Pass("clockgate", "extract clock gating out of flip flops") { } void help() override { @@ -60,6 +217,7 @@ struct ClockgatePass : public Pass { log(" user-specified ICG (integrated clock gating)\n"); log(" cell with ports named , , .\n"); log(" The ICG's clock enable pin must be active high.\n"); + // TODO -liberty log(" -tie_lo \n"); log(" Port of the ICG will be tied to zero.\n"); log(" Intended for DFT scan-enable pins.\n"); @@ -110,8 +268,9 @@ struct ClockgatePass : public Pass { std::optional pos_icg_desc; std::optional neg_icg_desc; - std::vector tie_lo_ports; + std::vector tie_lo_pins; int min_net_size = 0; + std::string liberty_file; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -125,14 +284,29 @@ struct ClockgatePass : public Pass { auto rest = args[++argidx]; neg_icg_desc = icg_from_arg(name, rest); } + if (args[argidx] == "-liberty" && argidx+1 < args.size()) { + liberty_file = args[++argidx]; + rewrite_filename(liberty_file); + } if (args[argidx] == "-tie_lo" && argidx+1 < args.size()) { - tie_lo_ports.push_back(RTLIL::escape_id(args[++argidx])); + tie_lo_pins.push_back(RTLIL::escape_id(args[++argidx])); } if (args[argidx] == "-min_net_size" && argidx+1 < args.size()) { min_net_size = atoi(args[++argidx].c_str()); } } + if (!liberty_file.empty()) + std::tie(pos_icg_desc, neg_icg_desc) = find_icgs(liberty_file); + else { + for (auto pin : tie_lo_pins) { + if (pos_icg_desc) + pos_icg_desc->tie_lo_pins.push_back(pin); + if (neg_icg_desc) + neg_icg_desc->tie_lo_pins.push_back(pin); + } + } + extra_args(args, argidx, design); pool ce_ffs; @@ -185,7 +359,7 @@ struct ClockgatePass : public Pass { gclk.new_net = module->addWire(NEW_ID); icg->setPort(matching_icg_desc->clk_out_pin, gclk.new_net); // Tie low DFT ports like scan chain enable - for (auto port : tie_lo_ports) + for (auto port : matching_icg_desc->tie_lo_pins) icg->setPort(port, Const(0, 1)); // Fix CE polarity if needed if (!clk.pol_ce) { From c921d85a852a462e6404a39bb844d92d3aca8d9b Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 18 Nov 2024 12:33:09 +0100 Subject: [PATCH 2/8] clockgate: fix test comments --- tests/techmap/clockgate.ys | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/techmap/clockgate.ys b/tests/techmap/clockgate.ys index dac4de0ec..84ccc0e92 100644 --- a/tests/techmap/clockgate.ys +++ b/tests/techmap/clockgate.ys @@ -61,7 +61,7 @@ clockgate -pos pdk_icg ce:clkin:clkout -tie_lo scanen # falling edge clock flops don't get matched on -pos select -module dffe_00 -assert-count 0 t:\\pdk_icg select -module dffe_01 -assert-count 0 t:\\pdk_icg -# falling edge clock flops do get matched on -pos +# rising edge clock flops do get matched on -pos select -module dffe_10 -assert-count 1 t:\\pdk_icg select -module dffe_11 -assert-count 1 t:\\pdk_icg # if necessary, EN is inverted, since the given ICG @@ -79,10 +79,10 @@ select -module dffe_wide_11 -assert-count 1 t:\\pdk_icg design -load before clockgate -min_net_size 1 -neg pdk_icg ce:clkin:clkout -tie_lo scanen -# rising edge clock flops don't get matched on -neg +# falling edge clock flops do get matched on -neg select -module dffe_00 -assert-count 1 t:\\pdk_icg select -module dffe_01 -assert-count 1 t:\\pdk_icg -# rising edge clock flops do get matched on -neg +# rising edge clock flops don't get matched on -neg select -module dffe_10 -assert-count 0 t:\\pdk_icg select -module dffe_11 -assert-count 0 t:\\pdk_icg # if necessary, EN is inverted, since the given ICG From 1e3f8cc630bc3573938753aae0b5346a7de4514f Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 18 Nov 2024 12:45:27 +0100 Subject: [PATCH 3/8] clockgate: add test liberty file --- tests/techmap/clockgate.lib | 107 ++++++++++++++++++++++++++++++++++++ tests/techmap/clockgate.ys | 40 +++++++++++++- 2 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 tests/techmap/clockgate.lib diff --git a/tests/techmap/clockgate.lib b/tests/techmap/clockgate.lib new file mode 100644 index 000000000..f231a131d --- /dev/null +++ b/tests/techmap/clockgate.lib @@ -0,0 +1,107 @@ +library(test) { + /* Integrated clock gating cells */ + cell (pos_big) { + area : 10; + clock_gating_integrated_cell : latch_posedge; + pin (GCLK) { + clock_gate_out_pin : true; + direction : output; + } + pin (CLK) { + clock_gate_clock_pin : true; + direction : input; + } + pin (CE) { + clock_gate_enable_pin : true; + direction : input; + } + } + cell (pos_small_tielo) { + area : 1; + clock_gating_integrated_cell : latch_posedge_precontrol; + pin (GCLK) { + clock_gate_out_pin : true; + direction : output; + } + pin (CLK) { + clock_gate_clock_pin : true; + direction : input; + } + pin (CE) { + clock_gate_enable_pin : true; + direction : input; + } + pin (SE) { + clock_gate_test_pin : true; + direction : input; + } + } + cell (pos_small) { + area : 1; + clock_gating_integrated_cell : latch_posedge; + pin (GCLK) { + clock_gate_out_pin : true; + direction : output; + } + pin (CLK) { + clock_gate_clock_pin : true; + direction : input; + } + pin (CE) { + clock_gate_enable_pin : true; + direction : input; + } + } + cell (neg_big) { + area : 10; + clock_gating_integrated_cell : latch_negedge; + pin (GCLK) { + clock_gate_out_pin : true; + direction : output; + } + pin (CLK) { + clock_gate_clock_pin : true; + direction : input; + } + pin (CE) { + clock_gate_enable_pin : true; + direction : input; + } + } + cell (neg_small_tielo) { + area : 1; + clock_gating_integrated_cell : latch_negedge_precontrol; + pin (GCLK) { + clock_gate_out_pin : true; + direction : output; + } + pin (CLK) { + clock_gate_clock_pin : true; + direction : input; + } + pin (CE) { + clock_gate_enable_pin : true; + direction : input; + } + pin (SE) { + clock_gate_test_pin : true; + direction : input; + } + } + cell (neg_small) { + area : 1; + clock_gating_integrated_cell : latch_negedge; + pin (GCLK) { + clock_gate_out_pin : true; + direction : output; + } + pin (CLK) { + clock_gate_clock_pin : true; + direction : input; + } + pin (CE) { + clock_gate_enable_pin : true; + direction : input; + } + } +} \ No newline at end of file diff --git a/tests/techmap/clockgate.ys b/tests/techmap/clockgate.ys index 84ccc0e92..34963adc4 100644 --- a/tests/techmap/clockgate.ys +++ b/tests/techmap/clockgate.ys @@ -193,4 +193,42 @@ select -assert-count 1 t:\\pdk_icg #------------------------------------------------------------------------------ -# TODO test -tie_lo +design -load before +clockgate -liberty clockgate.lib + +# rising edge ICGs +select -module dffe_00 -assert-count 0 t:\\pos_small +select -module dffe_01 -assert-count 0 t:\\pos_small + +select -module dffe_10 -assert-count 1 t:\\pos_small +select -module dffe_11 -assert-count 1 t:\\pos_small + +# falling edge ICGs +select -module dffe_00 -assert-count 1 t:\\neg_small +select -module dffe_01 -assert-count 1 t:\\neg_small + +select -module dffe_10 -assert-count 0 t:\\neg_small +select -module dffe_11 -assert-count 0 t:\\neg_small + +# and nothing else +select -module dffe_00 -assert-count 0 t:\\pos_big +select -module dffe_01 -assert-count 0 t:\\pos_big +select -module dffe_10 -assert-count 0 t:\\pos_big +select -module dffe_11 -assert-count 0 t:\\pos_big +select -module dffe_00 -assert-count 0 t:\\pos_small_tielo +select -module dffe_01 -assert-count 0 t:\\pos_small_tielo +select -module dffe_10 -assert-count 0 t:\\pos_small_tielo +select -module dffe_11 -assert-count 0 t:\\pos_small_tielo +select -module dffe_00 -assert-count 0 t:\\neg_big +select -module dffe_01 -assert-count 0 t:\\neg_big +select -module dffe_10 -assert-count 0 t:\\neg_big +select -module dffe_11 -assert-count 0 t:\\neg_big +select -module dffe_00 -assert-count 0 t:\\neg_small_tielo +select -module dffe_01 -assert-count 0 t:\\neg_small_tielo +select -module dffe_10 -assert-count 0 t:\\neg_small_tielo +select -module dffe_11 -assert-count 0 t:\\neg_small_tielo + +# if necessary, EN is inverted, since the given ICG +# is assumed to have an active-high EN +select -module dffe_10 -assert-count 1 t:\$_NOT_ +select -module dffe_11 -assert-count 0 t:\$_NOT_ From b08441d95ca3cef844f00bba93fffbe843b14873 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 18 Nov 2024 12:48:50 +0100 Subject: [PATCH 4/8] clockgate: shuffle test liberty to exercise comparison better --- tests/techmap/clockgate.lib | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/techmap/clockgate.lib b/tests/techmap/clockgate.lib index f231a131d..9f83baa55 100644 --- a/tests/techmap/clockgate.lib +++ b/tests/techmap/clockgate.lib @@ -1,21 +1,5 @@ library(test) { /* Integrated clock gating cells */ - cell (pos_big) { - area : 10; - clock_gating_integrated_cell : latch_posedge; - pin (GCLK) { - clock_gate_out_pin : true; - direction : output; - } - pin (CLK) { - clock_gate_clock_pin : true; - direction : input; - } - pin (CE) { - clock_gate_enable_pin : true; - direction : input; - } - } cell (pos_small_tielo) { area : 1; clock_gating_integrated_cell : latch_posedge_precontrol; @@ -36,6 +20,22 @@ library(test) { direction : input; } } + cell (pos_big) { + area : 10; + clock_gating_integrated_cell : latch_posedge; + pin (GCLK) { + clock_gate_out_pin : true; + direction : output; + } + pin (CLK) { + clock_gate_clock_pin : true; + direction : input; + } + pin (CE) { + clock_gate_enable_pin : true; + direction : input; + } + } cell (pos_small) { area : 1; clock_gating_integrated_cell : latch_posedge; From e6793da9a0aa3f41bf65b6e2382917e867065d03 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 18 Nov 2024 12:50:25 +0100 Subject: [PATCH 5/8] clockgate: refactor --- passes/techmap/clockgate.cc | 55 ++++++++++++++----------------------- 1 file changed, 20 insertions(+), 35 deletions(-) diff --git a/passes/techmap/clockgate.cc b/passes/techmap/clockgate.cc index 373440926..be41e3843 100644 --- a/passes/techmap/clockgate.cc +++ b/passes/techmap/clockgate.cc @@ -50,10 +50,7 @@ static std::pair, std::optional> auto ast = libparser.ast; // We will pick the most suitable ICG absed on tie_lo count and area - struct ICGRankable { - ClockGateCell icg; - double area; - }; + struct ICGRankable : public ClockGateCell { double area; }; std::optional best_pos; std::optional best_neg; @@ -78,32 +75,19 @@ static std::pair, std::optional> auto cell_name = cell->args[0]; auto icg_kind = icg_kind_ast->value; - std::vector kind_tags; - std::stringstream ss(icg_kind); - std::string tag; - while (std::getline(ss, tag, '_')) { - kind_tags.push_back(tag); - } - if ((kind_tags.size() < 2) || (kind_tags.size() > 4)) - log_error("Malformed liberty file - invalid clock_gating_integrated_cell value %s in cell %s\n", - icg_kind.c_str(), cell_name.c_str()); - auto internal = kind_tags[0]; - if (internal != "latch") { - // TODO Is this expected behavior? - log_warning("Skipping ICG cell %s - not latch-based\n", cell_name.c_str()); - continue; - } - auto clk_pol_tag = kind_tags[1]; + auto starts_with = [&](std::string prefix) { + return icg_kind.compare(0, prefix.size(), prefix) == 0; + }; bool clk_pol; - if (clk_pol_tag == "posedge") { + if (icg_kind == "latch_posedge" || starts_with("latch_posedge_")) { clk_pol = true; - } else if (clk_pol_tag == "negedge") { + } else if (icg_kind == "latch_negedge" || starts_with("latch_negedge_")) { clk_pol = false; } else { - log_error("Malformed liberty file - invalid clock_gating_integrated_cell value %s in cell %s\n", - icg_kind.c_str(), cell_name.c_str()); + log("Ignoring ICG primitive %s of kind '%s'\n", cell_name.c_str(), icg_kind.c_str()); continue; } + log_debug("maybe valid icg: %s\n", cell_name.c_str()); ClockGateCell icg_interface; icg_interface.name = RTLIL::escape_id(cell_name); @@ -112,7 +96,6 @@ static std::pair, std::optional> if (pin->id != "pin" || pin->args.size() != 1) continue; - log("Check pin %s\n", pin->args[0].c_str()); if (auto clk = pin->find("clock_gate_clock_pin")) { if (!icg_interface.clk_in_pin.empty()) log_error("Malformed liberty file - multiple clock_gate_clock_pin in cell %s\n", @@ -162,15 +145,17 @@ static std::pair, std::optional> bool winning = false; if (icg_to_beat) { - log_debug("ties: %zu ? %zu\n", icg_to_beat->icg.tie_lo_pins.size(), + log_debug("ties: %zu ? %zu\n", icg_to_beat->tie_lo_pins.size(), icg_interface.tie_lo_pins.size()); log_debug("area: %f ? %f\n", icg_to_beat->area, area); - if (icg_to_beat->icg.tie_lo_pins.size() != icg_interface.tie_lo_pins.size()) - winning = icg_to_beat->icg.tie_lo_pins.size() > icg_interface.tie_lo_pins.size(); - else - winning = icg_to_beat->area > area; + + // Prefer fewer test enables over area reduction (unlikely to matter) + auto goal = std::make_pair(icg_to_beat->tie_lo_pins.size(), icg_to_beat->area); + auto cost = std::make_pair(icg_interface.tie_lo_pins.size(), area); + winning = cost < goal; + if (winning) - log_debug("%s beats %s\n", icg_interface.name.c_str(), icg_to_beat->icg.name.c_str()); + log_debug("%s beats %s\n", icg_interface.name.c_str(), icg_to_beat->name.c_str()); } else { log_debug("%s is the first of its polarity\n", icg_interface.name.c_str()); winning = true; @@ -184,12 +169,12 @@ static std::pair, std::optional> std::optional pos; std::optional neg; if (best_pos) { - log("Selected rising edge ICG %s\n", best_pos->icg.name.c_str()); - pos.emplace(best_pos->icg); + log("Selected rising edge ICG %s\n", best_pos->name.c_str()); + pos.emplace(*best_pos); } if (best_neg) { - log("Selected falling edge ICG %s\n", best_neg->icg.name.c_str()); - neg.emplace(best_neg->icg); + log("Selected falling edge ICG %s\n", best_neg->name.c_str()); + neg.emplace(*best_neg); } return std::make_pair(pos, neg); } From a5bc36f77e57af59a059b20463e46cae13a7779c Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 18 Nov 2024 13:45:30 +0100 Subject: [PATCH 6/8] clockgate: add -dont_use --- passes/techmap/clockgate.cc | 28 ++++++++++++++++++++++------ tests/techmap/clockgate.ys | 13 +++++++++++++ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/passes/techmap/clockgate.cc b/passes/techmap/clockgate.cc index be41e3843..174895d9f 100644 --- a/passes/techmap/clockgate.cc +++ b/passes/techmap/clockgate.cc @@ -40,7 +40,7 @@ ClockGateCell icg_from_arg(std::string& name, std::string& str) { } static std::pair, std::optional> - find_icgs(std::string filename) { + find_icgs(std::string filename, std::vector const& dont_use_cells) { std::ifstream f; f.open(filename.c_str()); if (f.fail()) @@ -67,7 +67,17 @@ static std::pair, std::optional> if (dn != nullptr && dn->value == "true") continue; - // TODO Should we have user-specified dont_use_cells here? + bool dont_use = false; + for (auto dont_use_cell : dont_use_cells) + { + if (patmatch(dont_use_cell.c_str(), cell->args[0].c_str())) + { + dont_use = true; + break; + } + } + if (dont_use) + continue; const LibertyAst *icg_kind_ast = cell->find("clock_gating_integrated_cell"); if (icg_kind_ast == nullptr) @@ -254,8 +264,9 @@ struct ClockgatePass : public Pass { std::optional pos_icg_desc; std::optional neg_icg_desc; std::vector tie_lo_pins; - int min_net_size = 0; std::string liberty_file; + std::vector dont_use_cells; + int min_net_size = 0; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -269,12 +280,16 @@ struct ClockgatePass : public Pass { auto rest = args[++argidx]; neg_icg_desc = icg_from_arg(name, rest); } + if (args[argidx] == "-tie_lo" && argidx+1 < args.size()) { + tie_lo_pins.push_back(RTLIL::escape_id(args[++argidx])); + } if (args[argidx] == "-liberty" && argidx+1 < args.size()) { liberty_file = args[++argidx]; rewrite_filename(liberty_file); } - if (args[argidx] == "-tie_lo" && argidx+1 < args.size()) { - tie_lo_pins.push_back(RTLIL::escape_id(args[++argidx])); + if (args[argidx] == "-dont_use" && argidx+1 < args.size()) { + dont_use_cells.push_back(args[++argidx]); + continue; } if (args[argidx] == "-min_net_size" && argidx+1 < args.size()) { min_net_size = atoi(args[++argidx].c_str()); @@ -282,7 +297,8 @@ struct ClockgatePass : public Pass { } if (!liberty_file.empty()) - std::tie(pos_icg_desc, neg_icg_desc) = find_icgs(liberty_file); + std::tie(pos_icg_desc, neg_icg_desc) = + find_icgs(liberty_file, dont_use_cells); else { for (auto pin : tie_lo_pins) { if (pos_icg_desc) diff --git a/tests/techmap/clockgate.ys b/tests/techmap/clockgate.ys index 34963adc4..5bcabff00 100644 --- a/tests/techmap/clockgate.ys +++ b/tests/techmap/clockgate.ys @@ -232,3 +232,16 @@ select -module dffe_11 -assert-count 0 t:\\neg_small_tielo # is assumed to have an active-high EN select -module dffe_10 -assert-count 1 t:\$_NOT_ select -module dffe_11 -assert-count 0 t:\$_NOT_ + +#------------------------------------------------------------------------------ + +design -load before +clockgate -liberty clockgate.lib -dont_use pos_small -dont_use neg_small + +# rising edge ICGs +select -module dffe_10 -assert-count 1 t:\\pos_big +select -module dffe_11 -assert-count 1 t:\\pos_big + +# falling edge ICGs +select -module dffe_00 -assert-count 1 t:\\neg_big +select -module dffe_01 -assert-count 1 t:\\neg_big From 983c54c75f08cfcabfc03b30dac50f56847fa575 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 18 Nov 2024 13:57:49 +0100 Subject: [PATCH 7/8] clockgate: help string add -dont_use and -liberty --- passes/techmap/clockgate.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/passes/techmap/clockgate.cc b/passes/techmap/clockgate.cc index 174895d9f..f8076ef52 100644 --- a/passes/techmap/clockgate.cc +++ b/passes/techmap/clockgate.cc @@ -212,13 +212,20 @@ struct ClockgatePass : public Pass { log(" user-specified ICG (integrated clock gating)\n"); log(" cell with ports named , , .\n"); log(" The ICG's clock enable pin must be active high.\n"); - // TODO -liberty + log(" -liberty \n"); + log(" If specified, ICGs will be selected from the liberty file\n"); + log(" if available. Priority is given to cells with fewer tie_lo\n"); + log(" inputs and smaller size. This removes the need to manually\n"); + log(" specify -pos or -neg and -tie_lo.\n"); + log(" -dont_use \n"); + log(" Cells won't be considered when searching for ICGs\n"); + log(" in the liberty file specified by -liberty.\n"); log(" -tie_lo \n"); log(" Port of the ICG will be tied to zero.\n"); log(" Intended for DFT scan-enable pins.\n"); log(" -min_net_size \n"); log(" Only transform sets of at least eligible FFs.\n"); - // log(" \n"); + log(" \n"); } // One ICG will be generated per ClkNetInfo From 4d96cbec7592a3e4101f4b670942b3606f760ab6 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 18 Nov 2024 18:32:18 +0100 Subject: [PATCH 8/8] clockgate: reduce errors to warnings --- passes/techmap/clockgate.cc | 46 ++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/passes/techmap/clockgate.cc b/passes/techmap/clockgate.cc index f8076ef52..940884353 100644 --- a/passes/techmap/clockgate.cc +++ b/passes/techmap/clockgate.cc @@ -107,22 +107,25 @@ static std::pair, std::optional> continue; if (auto clk = pin->find("clock_gate_clock_pin")) { - if (!icg_interface.clk_in_pin.empty()) - log_error("Malformed liberty file - multiple clock_gate_clock_pin in cell %s\n", + if (!icg_interface.clk_in_pin.empty()) { + log_warning("Malformed liberty file - multiple clock_gate_clock_pin in cell %s\n", cell_name.c_str()); - else + continue; + } else icg_interface.clk_in_pin = RTLIL::escape_id(pin->args[0]); } else if (auto gclk = pin->find("clock_gate_out_pin")) { - if (!icg_interface.clk_out_pin.empty()) - log_error("Malformed liberty file - multiple clock_gate_out_pin in cell %s\n", + if (!icg_interface.clk_out_pin.empty()) { + log_warning("Malformed liberty file - multiple clock_gate_out_pin in cell %s\n", cell_name.c_str()); - else + continue; + } else icg_interface.clk_out_pin = RTLIL::escape_id(pin->args[0]); } else if (auto en = pin->find("clock_gate_enable_pin")) { - if (!icg_interface.ce_pin.empty()) - log_error("Malformed liberty file - multiple clock_gate_enable_pin in cell %s\n", + if (!icg_interface.ce_pin.empty()) { + log_warning("Malformed liberty file - multiple clock_gate_enable_pin in cell %s\n", cell_name.c_str()); - else + continue; + } else icg_interface.ce_pin = RTLIL::escape_id(pin->args[0]); } else if (auto se = pin->find("clock_gate_test_pin")) { icg_interface.tie_lo_pins.push_back(RTLIL::escape_id(pin->args[0])); @@ -131,20 +134,27 @@ static std::pair, std::optional> if (dir->value == "internal") continue; - log_error("Malformed liberty file - extra pin %s in cell %s\n", + log_warning("Malformed liberty file - extra pin %s in cell %s\n", pin->args[0].c_str(), cell_name.c_str()); + continue; } } - if (icg_interface.clk_in_pin.empty()) - log_error("Malformed liberty file - missing clock_gate_clock_pin in cell %s", + if (icg_interface.clk_in_pin.empty()) { + log_warning("Malformed liberty file - missing clock_gate_clock_pin in cell %s", cell_name.c_str()); - if (icg_interface.clk_out_pin.empty()) - log_error("Malformed liberty file - missing clock_gate_out_pin in cell %s", + continue; + } + if (icg_interface.clk_out_pin.empty()) { + log_warning("Malformed liberty file - missing clock_gate_out_pin in cell %s", cell_name.c_str()); - if (icg_interface.ce_pin.empty()) - log_error("Malformed liberty file - missing clock_gate_enable_pin in cell %s", + continue; + } + if (icg_interface.ce_pin.empty()) { + log_warning("Malformed liberty file - missing clock_gate_enable_pin in cell %s", cell_name.c_str()); + continue; + } double area = 0; const LibertyAst *ar = cell->find("area"); @@ -179,11 +189,11 @@ static std::pair, std::optional> std::optional pos; std::optional neg; if (best_pos) { - log("Selected rising edge ICG %s\n", best_pos->name.c_str()); + log("Selected rising edge ICG %s from Liberty file\n", best_pos->name.c_str()); pos.emplace(*best_pos); } if (best_neg) { - log("Selected falling edge ICG %s\n", best_neg->name.c_str()); + log("Selected falling edge ICG %s from Liberty file\n", best_neg->name.c_str()); neg.emplace(*best_neg); } return std::make_pair(pos, neg);