mirror of https://github.com/YosysHQ/yosys.git
libparse: add LibertyMergedCells, enable multiple -liberty args for dfflibmap and clockgate
This commit is contained in:
parent
60fb241cb3
commit
6edf9c86cb
|
@ -40,29 +40,15 @@ ClockGateCell icg_from_arg(std::string& name, std::string& str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::pair<std::optional<ClockGateCell>, std::optional<ClockGateCell>>
|
static std::pair<std::optional<ClockGateCell>, std::optional<ClockGateCell>>
|
||||||
find_icgs(std::string filename, std::vector<std::string> const& dont_use_cells) {
|
find_icgs(std::vector<const LibertyAst *> cells, 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
|
// We will pick the most suitable ICG absed on tie_lo count and area
|
||||||
struct ICGRankable : public ClockGateCell { double area; };
|
struct ICGRankable : public ClockGateCell { double area; };
|
||||||
std::optional<ICGRankable> best_pos;
|
std::optional<ICGRankable> best_pos;
|
||||||
std::optional<ICGRankable> best_neg;
|
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?
|
// This is a lot of boilerplate, isn't it?
|
||||||
for (auto cell : ast->children)
|
for (auto cell : cells)
|
||||||
{
|
{
|
||||||
if (cell->id != "cell" || cell->args.size() != 1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const LibertyAst *dn = cell->find("dont_use");
|
const LibertyAst *dn = cell->find("dont_use");
|
||||||
if (dn != nullptr && dn->value == "true")
|
if (dn != nullptr && dn->value == "true")
|
||||||
continue;
|
continue;
|
||||||
|
@ -223,7 +209,7 @@ struct ClockgatePass : public Pass {
|
||||||
log(" cell with ports named <ce>, <clk>, <gclk>.\n");
|
log(" cell with ports named <ce>, <clk>, <gclk>.\n");
|
||||||
log(" The ICG's clock enable pin must be active high.\n");
|
log(" The ICG's clock enable pin must be active high.\n");
|
||||||
log(" -liberty <filename>\n");
|
log(" -liberty <filename>\n");
|
||||||
log(" If specified, ICGs will be selected from the liberty file\n");
|
log(" If specified, ICGs will be selected from the liberty files\n");
|
||||||
log(" if available. Priority is given to cells with fewer tie_lo\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(" inputs and smaller size. This removes the need to manually\n");
|
||||||
log(" specify -pos or -neg and -tie_lo.\n");
|
log(" specify -pos or -neg and -tie_lo.\n");
|
||||||
|
@ -281,7 +267,7 @@ struct ClockgatePass : public Pass {
|
||||||
std::optional<ClockGateCell> pos_icg_desc;
|
std::optional<ClockGateCell> pos_icg_desc;
|
||||||
std::optional<ClockGateCell> neg_icg_desc;
|
std::optional<ClockGateCell> neg_icg_desc;
|
||||||
std::vector<std::string> tie_lo_pins;
|
std::vector<std::string> tie_lo_pins;
|
||||||
std::string liberty_file;
|
std::vector<std::string> liberty_files;
|
||||||
std::vector<std::string> dont_use_cells;
|
std::vector<std::string> dont_use_cells;
|
||||||
int min_net_size = 0;
|
int min_net_size = 0;
|
||||||
|
|
||||||
|
@ -304,8 +290,9 @@ struct ClockgatePass : public Pass {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (args[argidx] == "-liberty" && argidx+1 < args.size()) {
|
if (args[argidx] == "-liberty" && argidx+1 < args.size()) {
|
||||||
liberty_file = args[++argidx];
|
std::string liberty_file = args[++argidx];
|
||||||
rewrite_filename(liberty_file);
|
rewrite_filename(liberty_file);
|
||||||
|
liberty_files.push_back(liberty_file);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (args[argidx] == "-dont_use" && argidx+1 < args.size()) {
|
if (args[argidx] == "-dont_use" && argidx+1 < args.size()) {
|
||||||
|
@ -319,10 +306,20 @@ struct ClockgatePass : public Pass {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!liberty_file.empty())
|
if (!liberty_files.empty()) {
|
||||||
|
LibertyMergedCells merged;
|
||||||
|
for (auto path : liberty_files) {
|
||||||
|
std::ifstream f;
|
||||||
|
f.open(path.c_str());
|
||||||
|
if (f.fail())
|
||||||
|
log_cmd_error("Can't open liberty file `%s': %s\n", path.c_str(), strerror(errno));
|
||||||
|
LibertyParser p(f);
|
||||||
|
merged.merge(p);
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
std::tie(pos_icg_desc, neg_icg_desc) =
|
std::tie(pos_icg_desc, neg_icg_desc) =
|
||||||
find_icgs(liberty_file, dont_use_cells);
|
find_icgs(merged.cells, dont_use_cells);
|
||||||
else {
|
} else {
|
||||||
for (auto pin : tie_lo_pins) {
|
for (auto pin : tie_lo_pins) {
|
||||||
if (pos_icg_desc)
|
if (pos_icg_desc)
|
||||||
pos_icg_desc->tie_lo_pins.push_back(pin);
|
pos_icg_desc->tie_lo_pins.push_back(pin);
|
||||||
|
|
|
@ -229,7 +229,7 @@ static bool parse_pin(const LibertyAst *cell, const LibertyAst *attr, std::strin
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void find_cell(const LibertyAst *ast, IdString cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval, bool has_enable, bool enapol, std::vector<std::string> &dont_use_cells)
|
static void find_cell(std::vector<const LibertyAst *> cells, IdString cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval, bool has_enable, bool enapol, std::vector<std::string> &dont_use_cells)
|
||||||
{
|
{
|
||||||
const LibertyAst *best_cell = nullptr;
|
const LibertyAst *best_cell = nullptr;
|
||||||
std::map<std::string, char> best_cell_ports;
|
std::map<std::string, char> best_cell_ports;
|
||||||
|
@ -237,14 +237,8 @@ static void find_cell(const LibertyAst *ast, IdString cell_type, bool clkpol, bo
|
||||||
bool best_cell_noninv = false;
|
bool best_cell_noninv = false;
|
||||||
double best_cell_area = 0;
|
double best_cell_area = 0;
|
||||||
|
|
||||||
if (ast->id != "library")
|
for (auto cell : cells)
|
||||||
log_error("Format error in liberty file.\n");
|
|
||||||
|
|
||||||
for (auto cell : ast->children)
|
|
||||||
{
|
{
|
||||||
if (cell->id != "cell" || cell->args.size() != 1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const LibertyAst *dn = cell->find("dont_use");
|
const LibertyAst *dn = cell->find("dont_use");
|
||||||
if (dn != nullptr && dn->value == "true")
|
if (dn != nullptr && dn->value == "true")
|
||||||
continue;
|
continue;
|
||||||
|
@ -355,7 +349,7 @@ static void find_cell(const LibertyAst *ast, IdString cell_type, bool clkpol, bo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void find_cell_sr(const LibertyAst *ast, IdString cell_type, bool clkpol, bool setpol, bool clrpol, bool has_enable, bool enapol, std::vector<std::string> &dont_use_cells)
|
static void find_cell_sr(std::vector<const LibertyAst *> cells, IdString cell_type, bool clkpol, bool setpol, bool clrpol, bool has_enable, bool enapol, std::vector<std::string> &dont_use_cells)
|
||||||
{
|
{
|
||||||
const LibertyAst *best_cell = nullptr;
|
const LibertyAst *best_cell = nullptr;
|
||||||
std::map<std::string, char> best_cell_ports;
|
std::map<std::string, char> best_cell_ports;
|
||||||
|
@ -365,14 +359,8 @@ static void find_cell_sr(const LibertyAst *ast, IdString cell_type, bool clkpol,
|
||||||
|
|
||||||
log_assert(!enapol && "set/reset cell with enable is unimplemented due to lack of cells for testing");
|
log_assert(!enapol && "set/reset cell with enable is unimplemented due to lack of cells for testing");
|
||||||
|
|
||||||
if (ast->id != "library")
|
for (auto cell : cells)
|
||||||
log_error("Format error in liberty file.\n");
|
|
||||||
|
|
||||||
for (auto cell : ast->children)
|
|
||||||
{
|
{
|
||||||
if (cell->id != "cell" || cell->args.size() != 1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const LibertyAst *dn = cell->find("dont_use");
|
const LibertyAst *dn = cell->find("dont_use");
|
||||||
if (dn != nullptr && dn->value == "true")
|
if (dn != nullptr && dn->value == "true")
|
||||||
continue;
|
continue;
|
||||||
|
@ -561,7 +549,7 @@ struct DfflibmapPass : public Pass {
|
||||||
log(" dfflibmap [-prepare] [-map-only] [-info] [-dont_use <cell_name>] -liberty <file> [selection]\n");
|
log(" dfflibmap [-prepare] [-map-only] [-info] [-dont_use <cell_name>] -liberty <file> [selection]\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("Map internal flip-flop cells to the flip-flop cells in the technology\n");
|
log("Map internal flip-flop cells to the flip-flop cells in the technology\n");
|
||||||
log("library specified in the given liberty file.\n");
|
log("library specified in the given liberty files.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("This pass may add inverters as needed. Therefore it is recommended to\n");
|
log("This pass may add inverters as needed. Therefore it is recommended to\n");
|
||||||
log("first run this pass and then map the logic paths to the target technology.\n");
|
log("first run this pass and then map the logic paths to the target technology.\n");
|
||||||
|
@ -590,11 +578,11 @@ struct DfflibmapPass : public Pass {
|
||||||
log_header(design, "Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n");
|
log_header(design, "Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n");
|
||||||
log_push();
|
log_push();
|
||||||
|
|
||||||
std::string liberty_file;
|
|
||||||
bool prepare_mode = false;
|
bool prepare_mode = false;
|
||||||
bool map_only_mode = false;
|
bool map_only_mode = false;
|
||||||
bool info_mode = false;
|
bool info_mode = false;
|
||||||
|
|
||||||
|
std::vector<std::string> liberty_files;
|
||||||
std::vector<std::string> dont_use_cells;
|
std::vector<std::string> dont_use_cells;
|
||||||
|
|
||||||
size_t argidx;
|
size_t argidx;
|
||||||
|
@ -602,8 +590,9 @@ struct DfflibmapPass : public Pass {
|
||||||
{
|
{
|
||||||
std::string arg = args[argidx];
|
std::string arg = args[argidx];
|
||||||
if (arg == "-liberty" && argidx+1 < args.size()) {
|
if (arg == "-liberty" && argidx+1 < args.size()) {
|
||||||
liberty_file = args[++argidx];
|
std::string liberty_file = args[++argidx];
|
||||||
rewrite_filename(liberty_file);
|
rewrite_filename(liberty_file);
|
||||||
|
liberty_files.push_back(liberty_file);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (arg == "-prepare") {
|
if (arg == "-prepare") {
|
||||||
|
@ -636,41 +625,45 @@ struct DfflibmapPass : public Pass {
|
||||||
if (modes > 1)
|
if (modes > 1)
|
||||||
log_cmd_error("Only one of -prepare, -map-only, or -info options should be given!\n");
|
log_cmd_error("Only one of -prepare, -map-only, or -info options should be given!\n");
|
||||||
|
|
||||||
if (liberty_file.empty())
|
if (liberty_files.empty())
|
||||||
log_cmd_error("Missing `-liberty liberty_file' option!\n");
|
log_cmd_error("Missing `-liberty liberty_file' option!\n");
|
||||||
|
|
||||||
std::ifstream f;
|
LibertyMergedCells merged;
|
||||||
f.open(liberty_file.c_str());
|
for (auto path : liberty_files) {
|
||||||
if (f.fail())
|
std::ifstream f;
|
||||||
log_cmd_error("Can't open liberty file `%s': %s\n", liberty_file.c_str(), strerror(errno));
|
f.open(path.c_str());
|
||||||
LibertyParser libparser(f);
|
if (f.fail())
|
||||||
f.close();
|
log_cmd_error("Can't open liberty file `%s': %s\n", path.c_str(), strerror(errno));
|
||||||
|
LibertyParser p(f);
|
||||||
|
merged.merge(p);
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
|
||||||
find_cell(libparser.ast, ID($_DFF_N_), false, false, false, false, false, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFF_N_), false, false, false, false, false, false, dont_use_cells);
|
||||||
find_cell(libparser.ast, ID($_DFF_P_), true, false, false, false, false, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFF_P_), true, false, false, false, false, false, dont_use_cells);
|
||||||
|
|
||||||
find_cell(libparser.ast, ID($_DFF_NN0_), false, true, false, false, false, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFF_NN0_), false, true, false, false, false, false, dont_use_cells);
|
||||||
find_cell(libparser.ast, ID($_DFF_NN1_), false, true, false, true, false, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFF_NN1_), false, true, false, true, false, false, dont_use_cells);
|
||||||
find_cell(libparser.ast, ID($_DFF_NP0_), false, true, true, false, false, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFF_NP0_), false, true, true, false, false, false, dont_use_cells);
|
||||||
find_cell(libparser.ast, ID($_DFF_NP1_), false, true, true, true, false, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFF_NP1_), false, true, true, true, false, false, dont_use_cells);
|
||||||
find_cell(libparser.ast, ID($_DFF_PN0_), true, true, false, false, false, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFF_PN0_), true, true, false, false, false, false, dont_use_cells);
|
||||||
find_cell(libparser.ast, ID($_DFF_PN1_), true, true, false, true, false, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFF_PN1_), true, true, false, true, false, false, dont_use_cells);
|
||||||
find_cell(libparser.ast, ID($_DFF_PP0_), true, true, true, false, false, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFF_PP0_), true, true, true, false, false, false, dont_use_cells);
|
||||||
find_cell(libparser.ast, ID($_DFF_PP1_), true, true, true, true, false, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFF_PP1_), true, true, true, true, false, false, dont_use_cells);
|
||||||
|
|
||||||
find_cell(libparser.ast, ID($_DFFE_NN_), false, false, false, false, true, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFFE_NN_), false, false, false, false, true, false, dont_use_cells);
|
||||||
find_cell(libparser.ast, ID($_DFFE_NP_), false, false, false, false, true, true, dont_use_cells);
|
find_cell(merged.cells, ID($_DFFE_NP_), false, false, false, false, true, true, dont_use_cells);
|
||||||
find_cell(libparser.ast, ID($_DFFE_PN_), true, false, false, false, true, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFFE_PN_), true, false, false, false, true, false, dont_use_cells);
|
||||||
find_cell(libparser.ast, ID($_DFFE_PP_), true, false, false, false, true, true, dont_use_cells);
|
find_cell(merged.cells, ID($_DFFE_PP_), true, false, false, false, true, true, dont_use_cells);
|
||||||
|
|
||||||
find_cell_sr(libparser.ast, ID($_DFFSR_NNN_), false, false, false, false, false, dont_use_cells);
|
find_cell_sr(merged.cells, ID($_DFFSR_NNN_), false, false, false, false, false, dont_use_cells);
|
||||||
find_cell_sr(libparser.ast, ID($_DFFSR_NNP_), false, false, true, false, false, dont_use_cells);
|
find_cell_sr(merged.cells, ID($_DFFSR_NNP_), false, false, true, false, false, dont_use_cells);
|
||||||
find_cell_sr(libparser.ast, ID($_DFFSR_NPN_), false, true, false, false, false, dont_use_cells);
|
find_cell_sr(merged.cells, ID($_DFFSR_NPN_), false, true, false, false, false, dont_use_cells);
|
||||||
find_cell_sr(libparser.ast, ID($_DFFSR_NPP_), false, true, true, false, false, dont_use_cells);
|
find_cell_sr(merged.cells, ID($_DFFSR_NPP_), false, true, true, false, false, dont_use_cells);
|
||||||
find_cell_sr(libparser.ast, ID($_DFFSR_PNN_), true, false, false, false, false, dont_use_cells);
|
find_cell_sr(merged.cells, ID($_DFFSR_PNN_), true, false, false, false, false, dont_use_cells);
|
||||||
find_cell_sr(libparser.ast, ID($_DFFSR_PNP_), true, false, true, false, false, dont_use_cells);
|
find_cell_sr(merged.cells, ID($_DFFSR_PNP_), true, false, true, false, false, dont_use_cells);
|
||||||
find_cell_sr(libparser.ast, ID($_DFFSR_PPN_), true, true, false, false, false, dont_use_cells);
|
find_cell_sr(merged.cells, ID($_DFFSR_PPN_), true, true, false, false, false, dont_use_cells);
|
||||||
find_cell_sr(libparser.ast, ID($_DFFSR_PPP_), true, true, true, false, false, dont_use_cells);
|
find_cell_sr(merged.cells, ID($_DFFSR_PPP_), true, true, true, false, false, dont_use_cells);
|
||||||
|
|
||||||
log(" final dff cell mappings:\n");
|
log(" final dff cell mappings:\n");
|
||||||
logmap_all();
|
logmap_all();
|
||||||
|
|
|
@ -503,12 +503,12 @@ LibertyAst *LibertyParser::parse()
|
||||||
|
|
||||||
#ifndef FILTERLIB
|
#ifndef FILTERLIB
|
||||||
|
|
||||||
void LibertyParser::error()
|
void LibertyParser::error() const
|
||||||
{
|
{
|
||||||
log_error("Syntax error in liberty file on line %d.\n", line);
|
log_error("Syntax error in liberty file on line %d.\n", line);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibertyParser::error(const std::string &str)
|
void LibertyParser::error(const std::string &str) const
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Syntax error in liberty file on line " << line << ".\n";
|
ss << "Syntax error in liberty file on line " << line << ".\n";
|
||||||
|
@ -518,13 +518,13 @@ void LibertyParser::error(const std::string &str)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
void LibertyParser::error()
|
void LibertyParser::error() const
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Syntax error in liberty file on line %d.\n", line);
|
fprintf(stderr, "Syntax error in liberty file on line %d.\n", line);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibertyParser::error(const std::string &str)
|
void LibertyParser::error(const std::string &str) const
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Syntax error in liberty file on line " << line << ".\n";
|
ss << "Syntax error in liberty file on line " << line << ".\n";
|
||||||
|
|
|
@ -86,8 +86,10 @@ namespace Yosys
|
||||||
bool eval(dict<std::string, bool>& values);
|
bool eval(dict<std::string, bool>& values);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class LibertyMergedCells;
|
||||||
class LibertyParser
|
class LibertyParser
|
||||||
{
|
{
|
||||||
|
friend class LibertyMergedCells;
|
||||||
private:
|
private:
|
||||||
std::istream &f;
|
std::istream &f;
|
||||||
int line;
|
int line;
|
||||||
|
@ -100,8 +102,8 @@ namespace Yosys
|
||||||
int lexer(std::string &str);
|
int lexer(std::string &str);
|
||||||
|
|
||||||
LibertyAst *parse();
|
LibertyAst *parse();
|
||||||
void error();
|
void error() const;
|
||||||
void error(const std::string &str);
|
void error(const std::string &str) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const LibertyAst *ast;
|
const LibertyAst *ast;
|
||||||
|
@ -109,6 +111,35 @@ namespace Yosys
|
||||||
LibertyParser(std::istream &f) : f(f), line(1), ast(parse()) {}
|
LibertyParser(std::istream &f) : f(f), line(1), ast(parse()) {}
|
||||||
~LibertyParser() { if (ast) delete ast; }
|
~LibertyParser() { if (ast) delete ast; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class LibertyMergedCells
|
||||||
|
{
|
||||||
|
std::vector<const LibertyAst *> asts;
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::vector<const LibertyAst *> cells;
|
||||||
|
void merge(LibertyParser &parser)
|
||||||
|
{
|
||||||
|
if (parser.ast) {
|
||||||
|
const LibertyAst *ast = parser.ast;
|
||||||
|
asts.push_back(ast);
|
||||||
|
// The parser no longer owns its top level ast, but we do.
|
||||||
|
// sketchy zone
|
||||||
|
parser.ast = nullptr;
|
||||||
|
if (ast->id != "library")
|
||||||
|
parser.error("Top level entity isn't \"library\".\n");
|
||||||
|
for (const LibertyAst *cell : ast->children)
|
||||||
|
if (cell->id == "cell" && cell->args.size() == 1)
|
||||||
|
cells.push_back(cell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~LibertyMergedCells()
|
||||||
|
{
|
||||||
|
for (auto ast : asts)
|
||||||
|
delete ast;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -235,6 +235,49 @@ select -module dffe_11 -assert-count 0 t:\$_NOT_
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# test multiple liberty files to behave the same way
|
||||||
|
design -load before
|
||||||
|
clockgate -liberty clockgate_pos.lib -liberty clockgate_neg.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
|
design -load before
|
||||||
clockgate -liberty clockgate.lib -dont_use pos_small -dont_use neg_small
|
clockgate -liberty clockgate.lib -dont_use pos_small -dont_use neg_small
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
library(test) {
|
||||||
|
/* Integrated clock gating cells */
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -59,6 +59,16 @@ select -assert-count 1 t:dffn
|
||||||
select -assert-count 4 t:dffsr
|
select -assert-count 4 t:dffsr
|
||||||
select -assert-none t:dffn t:dffsr t:$_NOT_ %% %n t:* %i
|
select -assert-none t:dffn t:dffsr t:$_NOT_ %% %n t:* %i
|
||||||
|
|
||||||
|
design -load orig
|
||||||
|
dfflibmap -prepare -liberty dfflibmap_dffn.lib -liberty dfflibmap_dffsr.lib
|
||||||
|
dfflibmap -map-only -liberty dfflibmap_dffn.lib -liberty dfflibmap_dffsr.lib
|
||||||
|
clean
|
||||||
|
|
||||||
|
select -assert-count 4 t:$_NOT_
|
||||||
|
select -assert-count 1 t:dffn
|
||||||
|
select -assert-count 4 t:dffsr
|
||||||
|
select -assert-none t:dffn t:dffsr t:$_NOT_ %% %n t:* %i
|
||||||
|
|
||||||
design -load orig
|
design -load orig
|
||||||
dfflibmap -liberty dfflibmap.lib -dont_use *ffn
|
dfflibmap -liberty dfflibmap.lib -dont_use *ffn
|
||||||
clean
|
clean
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
library(test) {
|
||||||
|
cell (dffn) {
|
||||||
|
area : 6;
|
||||||
|
ff("IQ", "IQN") {
|
||||||
|
next_state : "D";
|
||||||
|
clocked_on : "!CLK";
|
||||||
|
}
|
||||||
|
pin(D) {
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
pin(CLK) {
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
pin(Q) {
|
||||||
|
direction: output;
|
||||||
|
function : "IQ";
|
||||||
|
}
|
||||||
|
pin(QN) {
|
||||||
|
direction: output;
|
||||||
|
function : "IQN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
library(test) {
|
||||||
|
cell (dffsr) {
|
||||||
|
area : 6;
|
||||||
|
ff("IQ", "IQN") {
|
||||||
|
next_state : "D";
|
||||||
|
clocked_on : "CLK";
|
||||||
|
clear : "CLEAR";
|
||||||
|
preset : "PRESET";
|
||||||
|
clear_preset_var1 : L;
|
||||||
|
clear_preset_var2 : L;
|
||||||
|
}
|
||||||
|
pin(D) {
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
pin(CLK) {
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
pin(CLEAR) {
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
pin(PRESET) {
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
pin(Q) {
|
||||||
|
direction: output;
|
||||||
|
function : "IQ";
|
||||||
|
}
|
||||||
|
pin(QN) {
|
||||||
|
direction: output;
|
||||||
|
function : "IQN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue