Skip to content

Commit

Permalink
Merge pull request #4797 from YosysHQ/emil/multiple-liberty
Browse files Browse the repository at this point in the history
Allow multiple -liberty args in dfflibmap and clockgate
  • Loading branch information
widlarizer authored Dec 4, 2024
2 parents 384c191 + 6edf9c8 commit 3b8e8ee
Show file tree
Hide file tree
Showing 10 changed files with 327 additions and 81 deletions.
47 changes: 25 additions & 22 deletions passes/techmap/clockgate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,29 +40,15 @@ ClockGateCell icg_from_arg(std::string& name, std::string& str) {
}

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;

find_icgs(std::vector<const LibertyAst *> cells, std::vector<std::string> const& dont_use_cells) {
// 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)
for (auto cell : cells)
{
if (cell->id != "cell" || cell->args.size() != 1)
continue;

const LibertyAst *dn = cell->find("dont_use");
if (dn != nullptr && dn->value == "true")
continue;
Expand Down Expand Up @@ -223,7 +209,7 @@ struct ClockgatePass : public Pass {
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 specified, ICGs will be selected from the liberty files\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");
Expand Down Expand Up @@ -281,7 +267,7 @@ struct ClockgatePass : public Pass {
std::optional<ClockGateCell> pos_icg_desc;
std::optional<ClockGateCell> neg_icg_desc;
std::vector<std::string> tie_lo_pins;
std::string liberty_file;
std::vector<std::string> liberty_files;
std::vector<std::string> dont_use_cells;
int min_net_size = 0;

Expand All @@ -291,32 +277,49 @@ struct ClockgatePass : public Pass {
auto name = args[++argidx];
auto rest = args[++argidx];
pos_icg_desc = icg_from_arg(name, rest);
continue;
}
if (args[argidx] == "-neg" && argidx+2 < args.size()) {
auto name = args[++argidx];
auto rest = args[++argidx];
neg_icg_desc = icg_from_arg(name, rest);
continue;
}
if (args[argidx] == "-tie_lo" && argidx+1 < args.size()) {
tie_lo_pins.push_back(RTLIL::escape_id(args[++argidx]));
continue;
}
if (args[argidx] == "-liberty" && argidx+1 < args.size()) {
liberty_file = args[++argidx];
std::string liberty_file = args[++argidx];
rewrite_filename(liberty_file);
liberty_files.push_back(liberty_file);
continue;
}
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());
continue;
}
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) =
find_icgs(liberty_file, dont_use_cells);
else {
find_icgs(merged.cells, dont_use_cells);
} else {
for (auto pin : tie_lo_pins) {
if (pos_icg_desc)
pos_icg_desc->tie_lo_pins.push_back(pin);
Expand Down
97 changes: 45 additions & 52 deletions passes/techmap/dfflibmap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -229,22 +229,16 @@ static bool parse_pin(const LibertyAst *cell, const LibertyAst *attr, std::strin
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;
std::map<std::string, char> best_cell_ports;
int best_cell_pins = 0;
bool best_cell_noninv = false;
double best_cell_area = 0;

if (ast->id != "library")
log_error("Format error in liberty file.\n");

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");
if (dn != nullptr && dn->value == "true")
continue;
Expand Down Expand Up @@ -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;
std::map<std::string, char> best_cell_ports;
Expand All @@ -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");

if (ast->id != "library")
log_error("Format error in liberty file.\n");

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");
if (dn != nullptr && dn->value == "true")
continue;
Expand Down Expand Up @@ -561,7 +549,7 @@ struct DfflibmapPass : public Pass {
log(" dfflibmap [-prepare] [-map-only] [-info] [-dont_use <cell_name>] -liberty <file> [selection]\n");
log("\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("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");
Expand Down Expand Up @@ -590,20 +578,21 @@ struct DfflibmapPass : public Pass {
log_header(design, "Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n");
log_push();

std::string liberty_file;
bool prepare_mode = false;
bool map_only_mode = false;
bool info_mode = false;

std::vector<std::string> liberty_files;
std::vector<std::string> dont_use_cells;

size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
std::string arg = args[argidx];
if (arg == "-liberty" && argidx+1 < args.size()) {
liberty_file = args[++argidx];
std::string liberty_file = args[++argidx];
rewrite_filename(liberty_file);
liberty_files.push_back(liberty_file);
continue;
}
if (arg == "-prepare") {
Expand Down Expand Up @@ -636,41 +625,45 @@ struct DfflibmapPass : public Pass {
if (modes > 1)
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");

std::ifstream f;
f.open(liberty_file.c_str());
if (f.fail())
log_cmd_error("Can't open liberty file `%s': %s\n", liberty_file.c_str(), strerror(errno));
LibertyParser libparser(f);
f.close();

find_cell(libparser.ast, 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(libparser.ast, 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(libparser.ast, 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(libparser.ast, 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(libparser.ast, 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(libparser.ast, 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(libparser.ast, 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_sr(libparser.ast, 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(libparser.ast, 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(libparser.ast, 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(libparser.ast, 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);
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();
}

find_cell(merged.cells, ID($_DFF_N_), false, 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(merged.cells, ID($_DFF_NN0_), false, true, false, false, false, false, dont_use_cells);
find_cell(merged.cells, ID($_DFF_NN1_), false, true, false, true, false, false, dont_use_cells);
find_cell(merged.cells, ID($_DFF_NP0_), false, true, true, false, false, false, dont_use_cells);
find_cell(merged.cells, ID($_DFF_NP1_), false, true, true, true, false, false, dont_use_cells);
find_cell(merged.cells, ID($_DFF_PN0_), true, true, false, false, false, false, dont_use_cells);
find_cell(merged.cells, ID($_DFF_PN1_), true, true, false, true, false, false, dont_use_cells);
find_cell(merged.cells, ID($_DFF_PP0_), true, true, true, false, false, false, dont_use_cells);
find_cell(merged.cells, ID($_DFF_PP1_), true, true, true, true, false, false, dont_use_cells);

find_cell(merged.cells, ID($_DFFE_NN_), false, false, false, false, true, false, dont_use_cells);
find_cell(merged.cells, ID($_DFFE_NP_), false, false, false, false, true, true, dont_use_cells);
find_cell(merged.cells, ID($_DFFE_PN_), true, false, false, false, true, false, dont_use_cells);
find_cell(merged.cells, ID($_DFFE_PP_), true, false, false, false, true, true, dont_use_cells);

find_cell_sr(merged.cells, ID($_DFFSR_NNN_), false, false, false, false, false, dont_use_cells);
find_cell_sr(merged.cells, ID($_DFFSR_NNP_), false, false, true, false, false, dont_use_cells);
find_cell_sr(merged.cells, ID($_DFFSR_NPN_), false, true, false, false, false, dont_use_cells);
find_cell_sr(merged.cells, ID($_DFFSR_NPP_), false, true, true, false, false, dont_use_cells);
find_cell_sr(merged.cells, ID($_DFFSR_PNN_), true, false, false, false, false, dont_use_cells);
find_cell_sr(merged.cells, ID($_DFFSR_PNP_), true, false, true, false, false, dont_use_cells);
find_cell_sr(merged.cells, ID($_DFFSR_PPN_), true, true, false, 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");
logmap_all();
Expand Down
8 changes: 4 additions & 4 deletions passes/techmap/libparse.cc
Original file line number Diff line number Diff line change
Expand Up @@ -503,12 +503,12 @@ LibertyAst *LibertyParser::parse()

#ifndef FILTERLIB

void LibertyParser::error()
void LibertyParser::error() const
{
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;
ss << "Syntax error in liberty file on line " << line << ".\n";
Expand All @@ -518,13 +518,13 @@ void LibertyParser::error(const std::string &str)

#else

void LibertyParser::error()
void LibertyParser::error() const
{
fprintf(stderr, "Syntax error in liberty file on line %d.\n", line);
exit(1);
}

void LibertyParser::error(const std::string &str)
void LibertyParser::error(const std::string &str) const
{
std::stringstream ss;
ss << "Syntax error in liberty file on line " << line << ".\n";
Expand Down
37 changes: 34 additions & 3 deletions passes/techmap/libparse.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,10 @@ namespace Yosys
bool eval(dict<std::string, bool>& values);
};

class LibertyMergedCells;
class LibertyParser
{
friend class LibertyMergedCells;
private:
std::istream &f;
int line;
Expand All @@ -98,17 +100,46 @@ namespace Yosys
anything else is a single character.
*/
int lexer(std::string &str);

LibertyAst *parse();
void error();
void error(const std::string &str);
void error() const;
void error(const std::string &str) const;

public:
const LibertyAst *ast;

LibertyParser(std::istream &f) : f(f), line(1), ast(parse()) {}
~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
Loading

0 comments on commit 3b8e8ee

Please sign in to comment.