mirror of https://github.com/YosysHQ/yosys.git
Compare commits
29 Commits
d69b4a3b6a
...
7484cce42a
Author | SHA1 | Date |
---|---|---|
Martin Povišer | 7484cce42a | |
George Rennie | 18b616578a | |
Emil J | 5b6baa3ef1 | |
Martin Povišer | 53a4ec375b | |
George Rennie | 9043dc0ad6 | |
Emil J | 56b80bdd22 | |
Emil J | da8c8b4fd0 | |
Emil J | cc17d5bb70 | |
Emil J | 18459b4b09 | |
Emil J | 88abc4c20f | |
Martin Povišer | 7ebe451f9a | |
Emil J. Tywoniak | 4d96cbec75 | |
Emil J. Tywoniak | 983c54c75f | |
Emil J. Tywoniak | a5bc36f77e | |
Emil J. Tywoniak | e6793da9a0 | |
Emil J. Tywoniak | b08441d95c | |
Emil J. Tywoniak | 1e3f8cc630 | |
Emil J. Tywoniak | c921d85a85 | |
Pepijn de Vos | b8329df1d0 | |
Emil J. Tywoniak | 45880ea7f2 | |
George Rennie | c23e64a236 | |
George Rennie | 626dbbe1e0 | |
George Rennie | de728c9824 | |
George Rennie | 0572f8806f | |
George Rennie | 023f029dcf | |
George Rennie | e105cae4a9 | |
George Rennie | 58af70624f | |
George Rennie | 41aaaa153e | |
Martin Povišer | 6f7f71fe03 |
|
@ -362,17 +362,17 @@ void parse_blif(RTLIL::Design *design, std::istream &f, IdString dff_name, bool
|
|||
goto no_latch_clock;
|
||||
|
||||
if (!strcmp(edge, "re"))
|
||||
cell = module->addDff(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q));
|
||||
cell = module->addDffGate(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q));
|
||||
else if (!strcmp(edge, "fe"))
|
||||
cell = module->addDff(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q), false);
|
||||
cell = module->addDffGate(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q), false);
|
||||
else if (!strcmp(edge, "ah"))
|
||||
cell = module->addDlatch(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q));
|
||||
cell = module->addDlatchGate(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q));
|
||||
else if (!strcmp(edge, "al"))
|
||||
cell = module->addDlatch(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q), false);
|
||||
cell = module->addDlatchGate(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q), false);
|
||||
else {
|
||||
no_latch_clock:
|
||||
if (dff_name.empty()) {
|
||||
cell = module->addFf(NEW_ID, blif_wire(d), blif_wire(q));
|
||||
cell = module->addFfGate(NEW_ID, blif_wire(d), blif_wire(q));
|
||||
} else {
|
||||
cell = module->addCell(NEW_ID, dff_name);
|
||||
cell->setPort(ID::D, blif_wire(d));
|
||||
|
|
|
@ -1273,6 +1273,11 @@ class WFunction:
|
|||
func.duplicate = False
|
||||
func.namespace = namespace
|
||||
str_def = str_def.replace("operator ","operator")
|
||||
|
||||
# remove attributes from the start
|
||||
if str.startswith(str_def, "[[") and "]]" in str_def:
|
||||
str_def = str_def[str_def.find("]]")+2:]
|
||||
|
||||
if str.startswith(str_def, "static "):
|
||||
func.is_static = True
|
||||
str_def = str_def[7:]
|
||||
|
@ -1574,10 +1579,15 @@ class WFunction:
|
|||
return_stmt = "return " if self.ret_type.name != "void" else ""
|
||||
|
||||
text += ")\n\t\t{"
|
||||
text += "\n\t\t\tif (boost::python::override py_" + self.alias + " = this->get_override(\"py_" + self.alias + "\"))"
|
||||
text += f"\n\t\t\t\t{return_stmt}" + call_string
|
||||
text += "\n\t\t\telse"
|
||||
text += "\n\t\t\tif (boost::python::override py_" + self.alias + " = this->get_override(\"py_" + self.alias + "\")) {"
|
||||
text += "\n\t\t\t\ttry {"
|
||||
text += f"\n\t\t\t\t\t{return_stmt}" + call_string
|
||||
text += "\n\t\t\t\t} catch (boost::python::error_already_set &) {"
|
||||
text += "\n\t\t\t\t\tlog_python_exception_as_error();"
|
||||
text += "\n\t\t\t\t}"
|
||||
text += "\n\t\t\t} else {"
|
||||
text += f"\n\t\t\t\t{return_stmt}" + self.member_of.name + "::" + call_string
|
||||
text += "\n\t\t\t}"
|
||||
text += "\n\t\t}"
|
||||
|
||||
text += "\n\n\t\t" + self.ret_type.gen_text() + " default_py_" + self.alias + "("
|
||||
|
@ -2330,6 +2340,11 @@ USING_YOSYS_NAMESPACE
|
|||
|
||||
namespace YOSYS_PYTHON {
|
||||
|
||||
[[noreturn]] static void log_python_exception_as_error() {
|
||||
PyErr_Print();
|
||||
log_error("Python interpreter encountered an exception.\\n");
|
||||
}
|
||||
|
||||
struct YosysStatics{};
|
||||
""")
|
||||
|
||||
|
|
|
@ -39,6 +39,10 @@ void demorgan_worker(
|
|||
return;
|
||||
|
||||
auto insig = sigmap(cell->getPort(ID::A));
|
||||
|
||||
if (GetSize(insig) < 1)
|
||||
return;
|
||||
|
||||
log("Inspecting %s cell %s (%d inputs)\n", log_id(cell->type), log_id(cell->name), GetSize(insig));
|
||||
int num_inverted = 0;
|
||||
for(int i=0; i<GetSize(insig); i++)
|
||||
|
|
|
@ -89,6 +89,9 @@ struct OptReduceWorker
|
|||
RTLIL::SigSpec new_sig_a(new_sig_a_bits);
|
||||
new_sig_a.sort_and_unify();
|
||||
|
||||
if (GetSize(new_sig_a) == 0)
|
||||
new_sig_a = (cell->type == ID($reduce_or)) ? State::S0 : State::S1;
|
||||
|
||||
if (new_sig_a != sig_a || sig_a.size() != cell->getPort(ID::A).size()) {
|
||||
log(" New input vector for %s cell %s: %s\n", cell->type.c_str(), cell->name.c_str(), log_signal(new_sig_a));
|
||||
did_something = true;
|
||||
|
|
|
@ -53,6 +53,11 @@ match add
|
|||
select port(add, constport).is_fully_const()
|
||||
define <IdString> varport (constport == \A ? \B : \A)
|
||||
|
||||
// only optimize for constants up to a fixed width. this prevents cases
|
||||
// with a blowup in internal term size and prevents larger constants being
|
||||
// casted to int incorrectly
|
||||
select (GetSize(port(add, constport)) <= 24)
|
||||
|
||||
// if a value of var is able to wrap the output, the transformation might give wrong results
|
||||
// an addition/substraction can at most flip one more bit than the largest operand (the carry bit)
|
||||
// as long as the output can show this bit, no wrap should occur (assuming all signed-ness make sense)
|
||||
|
|
|
@ -262,7 +262,7 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
|
|||
{
|
||||
log_warning("Complex async reset for dff `%s'.\n", log_signal(sig));
|
||||
gen_dffsr_complex(mod, insig, sig, sync_edge->signal, sync_edge->type == RTLIL::SyncType::STp, async_rules, proc);
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If there is a reset condition in the async rules, use it
|
||||
|
@ -277,7 +277,7 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
|
|||
sync_edge->type == RTLIL::SyncType::STp,
|
||||
sync_level && sync_level->type == RTLIL::SyncType::ST1,
|
||||
sync_edge->signal, sync_level->signal, proc);
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
gen_dff(mod, insig, rstval.as_const(), sig_q,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "kernel/yosys.h"
|
||||
#include "kernel/ff.h"
|
||||
#include "libparse.h"
|
||||
#include <optional>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
@ -10,6 +11,7 @@ struct ClockGateCell {
|
|||
IdString ce_pin;
|
||||
IdString clk_in_pin;
|
||||
IdString clk_out_pin;
|
||||
std::vector<IdString> tie_lo_pins;
|
||||
};
|
||||
|
||||
ClockGateCell icg_from_arg(std::string& name, std::string& str) {
|
||||
|
@ -37,6 +39,166 @@ ClockGateCell icg_from_arg(std::string& name, std::string& str) {
|
|||
return c;
|
||||
}
|
||||
|
||||
static std::pair<std::optional<ClockGateCell>, std::optional<ClockGateCell>>
|
||||
find_icgs(std::string filename, std::vector<std::string> const& dont_use_cells) {
|
||||
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 : public ClockGateCell { double area; };
|
||||
std::optional<ICGRankable> best_pos;
|
||||
std::optional<ICGRankable> 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;
|
||||
|
||||
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)
|
||||
continue;
|
||||
|
||||
auto cell_name = cell->args[0];
|
||||
auto icg_kind = icg_kind_ast->value;
|
||||
auto starts_with = [&](std::string prefix) {
|
||||
return icg_kind.compare(0, prefix.size(), prefix) == 0;
|
||||
};
|
||||
bool clk_pol;
|
||||
if (icg_kind == "latch_posedge" || starts_with("latch_posedge_")) {
|
||||
clk_pol = true;
|
||||
} else if (icg_kind == "latch_negedge" || starts_with("latch_negedge_")) {
|
||||
clk_pol = false;
|
||||
} else {
|
||||
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);
|
||||
|
||||
for (auto pin : cell->children) {
|
||||
if (pin->id != "pin" || pin->args.size() != 1)
|
||||
continue;
|
||||
|
||||
if (auto clk = pin->find("clock_gate_clock_pin")) {
|
||||
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());
|
||||
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_warning("Malformed liberty file - multiple clock_gate_out_pin in cell %s\n",
|
||||
cell_name.c_str());
|
||||
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_warning("Malformed liberty file - multiple clock_gate_enable_pin in cell %s\n",
|
||||
cell_name.c_str());
|
||||
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]));
|
||||
} else {
|
||||
const LibertyAst *dir = pin->find("direction");
|
||||
if (dir->value == "internal")
|
||||
continue;
|
||||
|
||||
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_warning("Malformed liberty file - missing clock_gate_clock_pin in cell %s",
|
||||
cell_name.c_str());
|
||||
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());
|
||||
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");
|
||||
if (ar != nullptr && !ar->value.empty())
|
||||
area = atof(ar->value.c_str());
|
||||
|
||||
std::optional<ICGRankable>& 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->tie_lo_pins.size(),
|
||||
icg_interface.tie_lo_pins.size());
|
||||
log_debug("area: %f ? %f\n", 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->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<ClockGateCell> pos;
|
||||
std::optional<ClockGateCell> neg;
|
||||
if (best_pos) {
|
||||
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 from Liberty file\n", best_neg->name.c_str());
|
||||
neg.emplace(*best_neg);
|
||||
}
|
||||
return std::make_pair(pos, neg);
|
||||
}
|
||||
|
||||
struct ClockgatePass : public Pass {
|
||||
ClockgatePass() : Pass("clockgate", "extract clock gating out of flip flops") { }
|
||||
void help() override {
|
||||
|
@ -60,12 +222,20 @@ struct ClockgatePass : public Pass {
|
|||
log(" user-specified <celltype> ICG (integrated clock gating)\n");
|
||||
log(" cell with ports named <ce>, <clk>, <gclk>.\n");
|
||||
log(" The ICG's clock enable pin must be active high.\n");
|
||||
log(" -liberty <filename>\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 <celltype>\n");
|
||||
log(" Cells <celltype> won't be considered when searching for ICGs\n");
|
||||
log(" in the liberty file specified by -liberty.\n");
|
||||
log(" -tie_lo <port_name>\n");
|
||||
log(" Port <port_name> of the ICG will be tied to zero.\n");
|
||||
log(" Intended for DFT scan-enable pins.\n");
|
||||
log(" -min_net_size <n>\n");
|
||||
log(" Only transform sets of at least <n> eligible FFs.\n");
|
||||
// log(" \n");
|
||||
log(" \n");
|
||||
}
|
||||
|
||||
// One ICG will be generated per ClkNetInfo
|
||||
|
@ -110,7 +280,9 @@ struct ClockgatePass : public Pass {
|
|||
|
||||
std::optional<ClockGateCell> pos_icg_desc;
|
||||
std::optional<ClockGateCell> neg_icg_desc;
|
||||
std::vector<std::string> tie_lo_ports;
|
||||
std::vector<std::string> tie_lo_pins;
|
||||
std::string liberty_file;
|
||||
std::vector<std::string> dont_use_cells;
|
||||
int min_net_size = 0;
|
||||
|
||||
size_t argidx;
|
||||
|
@ -126,13 +298,33 @@ struct ClockgatePass : public Pass {
|
|||
neg_icg_desc = icg_from_arg(name, rest);
|
||||
}
|
||||
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] == "-liberty" && argidx+1 < args.size()) {
|
||||
liberty_file = args[++argidx];
|
||||
rewrite_filename(liberty_file);
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
if (!liberty_file.empty())
|
||||
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)
|
||||
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<Cell*> ce_ffs;
|
||||
|
@ -185,7 +377,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) {
|
||||
|
|
|
@ -65,6 +65,8 @@ if __name__ == '__main__':
|
|||
|
||||
dirs = [
|
||||
os.path.join(args.gowin_dir, 'IDE/simlib/gw1n/'),
|
||||
os.path.join(args.gowin_dir, 'IDE/simlib/gw2a/'),
|
||||
os.path.join(args.gowin_dir, 'IDE/simlib/gw5a/'),
|
||||
]
|
||||
|
||||
with open('cells_xtra.v', 'w') as fout:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,15 @@
|
|||
read_rtlil <<EOT
|
||||
autoidx 1
|
||||
module \top
|
||||
wire output 1 \Y
|
||||
cell $reduce_or $reduce_or$rtl.v:29$20
|
||||
parameter \A_SIGNED 0
|
||||
parameter \A_WIDTH 0
|
||||
parameter \Y_WIDTH 1
|
||||
connect \A { }
|
||||
connect \Y \Y
|
||||
end
|
||||
end
|
||||
EOT
|
||||
|
||||
equiv_opt -assert opt_demorgan
|
|
@ -0,0 +1,14 @@
|
|||
# Check that opt_reduce doesn't produce zero width $reduce_or/$reduce_and,
|
||||
|
||||
read_verilog <<EOT
|
||||
module reduce_const(output wire o, output wire a);
|
||||
wire [3:0] zero = 4'b0000;
|
||||
wire [3:0] ones = 4'b1111;
|
||||
assign o = |zero;
|
||||
assign a = &ones;
|
||||
endmodule
|
||||
EOT
|
||||
|
||||
equiv_opt -assert opt_reduce
|
||||
design -load postopt
|
||||
select -assert-none r:A_WIDTH=0
|
|
@ -0,0 +1,31 @@
|
|||
read_rtlil <<EOT
|
||||
autoidx 1
|
||||
module \top
|
||||
wire input 1 \clk
|
||||
wire input 2 \rst
|
||||
|
||||
wire input 3 \a_r
|
||||
wire input 4 \a_n
|
||||
wire input 5 \b_n
|
||||
|
||||
wire \a
|
||||
wire \b
|
||||
|
||||
process $proc
|
||||
sync high \rst
|
||||
update \a \a_r
|
||||
update \b \b
|
||||
sync posedge \clk
|
||||
update \a \a_n
|
||||
update \b \b_n
|
||||
end
|
||||
end
|
||||
EOT
|
||||
|
||||
proc_dff
|
||||
proc_clean
|
||||
|
||||
# Processes should have been converted to one aldff and one dff
|
||||
select -assert-none p:*
|
||||
select -assert-count 1 t:$aldff
|
||||
select -assert-count 1 t:$dff
|
|
@ -0,0 +1,107 @@
|
|||
library(test) {
|
||||
/* Integrated clock gating cells */
|
||||
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_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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
@ -193,4 +193,55 @@ 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_
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue