Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
widlarizer committed Sep 4, 2024
1 parent b71219b commit 33e06df
Showing 1 changed file with 124 additions and 25 deletions.
149 changes: 124 additions & 25 deletions passes/techmap/clock_gate.cc
Original file line number Diff line number Diff line change
@@ -1,9 +1,39 @@
#include "kernel/yosys.h"
#include "kernel/ff.h"
#include <optional>

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct ClockGateCell {
std::string name;
std::string ce_pin;
std::string clk_in_pin;
std::string clk_out_pin;

ClockGateCell(std::string& name, std::string& str) : name(RTLIL::escape_id(name)) {
char delimiter = ':';
size_t pos1 = str.find(delimiter);
if (pos1 == std::string::npos)
log_assert(false && "Not enough ports in descriptor string");
size_t pos2 = str.find(delimiter, pos1 + 1);
if (pos2 == std::string::npos)
log_assert(false && "Not enough ports in descriptor string");
size_t pos3 = str.find(delimiter, pos2 + 1);
if (pos3 != std::string::npos)
log_assert(false && "Too many ports in descriptor string");

ce_pin = str.substr(0, pos1);
ce_pin = RTLIL::escape_id(ce_pin);

clk_in_pin = str.substr(pos1 + 1, pos2 - (pos1 + 1));
clk_in_pin = RTLIL::escape_id(clk_in_pin);

clk_out_pin = str.substr(pos2 + 1, str.size() - (pos2 + 1));
clk_out_pin = RTLIL::escape_id(clk_out_pin);
}
};

struct ClockgatePass : public Pass {
ClockgatePass() : Pass("clock_gate", "extract clock gating out of flip flops") { }
void help() override
Expand All @@ -18,43 +48,112 @@ struct ClockgatePass : public Pass {
{
log_header(design, "Executing CLOCK_GATE pass (extract clock gating out of flip flops).\n");

std::string pos_icg_cell;
std::string neg_icg_cell;
std::optional<ClockGateCell> pos_icg_desc;
std::optional<ClockGateCell> neg_icg_desc;
std::vector<std::string> tie_lo_ports;
int net_size = 0;

size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-pos" && argidx+1 < args.size()) {
pos_icg_cell = args[++argidx];
if (args[argidx] == "-pos" && argidx+2 < args.size()) {
auto name = args[++argidx];
auto rest = args[++argidx];
pos_icg_desc = ClockGateCell(name, rest);
}
if (args[argidx] == "-neg" && argidx+1 < args.size()) {
neg_icg_cell = args[++argidx];
if (args[argidx] == "-neg" && argidx+2 < args.size()) {
auto name = args[++argidx];
auto rest = args[++argidx];
neg_icg_desc = ClockGateCell(name, rest);
}
if (args[argidx] == "-tie_lo" && argidx+1 < args.size()) {
tie_lo_ports.push_back(RTLIL::escape_id(args[++argidx]));
}
if (args[argidx] == "-net_size" && argidx+1 < args.size()) {
net_size = atoi(args[++argidx].c_str());
}
break;
}

// TODO worker?

extra_args(args, argidx, design);

pool<Cell*> ce_ffs;
dict<Wire*, int> clk_net_sizes;
int gated_flop_count = 0;
for (auto module : design->selected_whole_modules()) {
sigmap.set(module);
sigmap.set(module);
initvals.set(&sigmap, module);
for (auto cell : module->cells()) {
if (!RTLIL::builtin_ff_cell_types().count(cell->type))
continue;
FfData ff(&initvals, cell);
if (ff.has_ce) {

// TODO do stuff


bool ce_pol = ff.pol_ce;
if (!ce_pol) {
//TODO invert CE
}
}
}
}
for (auto cell : module->cells()) {
if (!RTLIL::builtin_ff_cell_types().count(cell->type))
continue;

FfData ff(&initvals, cell);
if (ff.has_ce) {
ce_ffs.insert(cell);

Wire* clk = ff.sig_clk.as_wire();
auto it = clk_net_sizes.find(clk);
if (it != clk_net_sizes.end())
it->second++;
else
clk_net_sizes[clk] = 1;
}
}

for (auto cell : ce_ffs) {
FfData ff(&initvals, cell);

Wire* clk = ff.sig_clk.as_wire();
if (clk_net_sizes[clk] < net_size)
continue;

std::string name = cell->name.str() + "_ICG";
std::optional<ClockGateCell> matching_icg_desc;

if (pos_icg_desc && ff.pol_clk)
matching_icg_desc = pos_icg_desc;
else if (neg_icg_desc && !ff.pol_clk)
matching_icg_desc = neg_icg_desc;

if (!matching_icg_desc)
continue;

// Read CE polarity before doing anything
bool ce_pol = ff.pol_ce;
// Now we start messing with the design
ff.has_ce = false;
// Construct the clock gate
// ICG = integrated clock gate, industry shorthand
Cell* icg = module->addCell(name, matching_icg_desc->name);
icg->setPort(matching_icg_desc->ce_pin, ff.sig_ce);
icg->setPort(matching_icg_desc->clk_in_pin, ff.sig_clk);

Wire *new_gclk = module->addWire(NEW_ID);
ff.sig_clk = new_gclk;
icg->setPort(matching_icg_desc->clk_out_pin, ff.sig_clk);

// Tie low DFT ports like scan chain enable
for (auto port : tie_lo_ports)
icg->setPort(port, Const(0));

// Rebuild the flop
(void)ff.emit();

// Fix CE polarity if needed
if (!ce_pol) {
SigBit ce_fixed_pol = ff.module->NotGate(NEW_ID, ff.sig_ce);
icg->setPort(matching_icg_desc->ce_pin, ce_fixed_pol);
}
gated_flop_count++;
}
ce_ffs.clear();
clk_net_sizes.clear();
}

// TODO add tests like tests/sim/dffe.v
// TODO we currently create one ICG per flop!

log("Converted %d FFs.\n", gated_flop_count);
}
} ClockgatePass;

Expand Down

0 comments on commit 33e06df

Please sign in to comment.