Skip to content

Commit 6edf9c8

Browse files
committed
libparse: add LibertyMergedCells, enable multiple -liberty args for dfflibmap and clockgate
1 parent 60fb241 commit 6edf9c8

File tree

10 files changed

+321
-81
lines changed

10 files changed

+321
-81
lines changed

passes/techmap/clockgate.cc

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -40,29 +40,15 @@ ClockGateCell icg_from_arg(std::string& name, std::string& str) {
4040
}
4141

4242
static std::pair<std::optional<ClockGateCell>, std::optional<ClockGateCell>>
43-
find_icgs(std::string filename, std::vector<std::string> const& dont_use_cells) {
44-
std::ifstream f;
45-
f.open(filename.c_str());
46-
if (f.fail())
47-
log_cmd_error("Can't open liberty file `%s': %s\n", filename.c_str(), strerror(errno));
48-
LibertyParser libparser(f);
49-
f.close();
50-
auto ast = libparser.ast;
51-
43+
find_icgs(std::vector<const LibertyAst *> cells, std::vector<std::string> const& dont_use_cells) {
5244
// We will pick the most suitable ICG absed on tie_lo count and area
5345
struct ICGRankable : public ClockGateCell { double area; };
5446
std::optional<ICGRankable> best_pos;
5547
std::optional<ICGRankable> best_neg;
5648

57-
if (ast->id != "library")
58-
log_error("Format error in liberty file.\n");
59-
6049
// This is a lot of boilerplate, isn't it?
61-
for (auto cell : ast->children)
50+
for (auto cell : cells)
6251
{
63-
if (cell->id != "cell" || cell->args.size() != 1)
64-
continue;
65-
6652
const LibertyAst *dn = cell->find("dont_use");
6753
if (dn != nullptr && dn->value == "true")
6854
continue;
@@ -223,7 +209,7 @@ struct ClockgatePass : public Pass {
223209
log(" cell with ports named <ce>, <clk>, <gclk>.\n");
224210
log(" The ICG's clock enable pin must be active high.\n");
225211
log(" -liberty <filename>\n");
226-
log(" If specified, ICGs will be selected from the liberty file\n");
212+
log(" If specified, ICGs will be selected from the liberty files\n");
227213
log(" if available. Priority is given to cells with fewer tie_lo\n");
228214
log(" inputs and smaller size. This removes the need to manually\n");
229215
log(" specify -pos or -neg and -tie_lo.\n");
@@ -281,7 +267,7 @@ struct ClockgatePass : public Pass {
281267
std::optional<ClockGateCell> pos_icg_desc;
282268
std::optional<ClockGateCell> neg_icg_desc;
283269
std::vector<std::string> tie_lo_pins;
284-
std::string liberty_file;
270+
std::vector<std::string> liberty_files;
285271
std::vector<std::string> dont_use_cells;
286272
int min_net_size = 0;
287273

@@ -304,8 +290,9 @@ struct ClockgatePass : public Pass {
304290
continue;
305291
}
306292
if (args[argidx] == "-liberty" && argidx+1 < args.size()) {
307-
liberty_file = args[++argidx];
293+
std::string liberty_file = args[++argidx];
308294
rewrite_filename(liberty_file);
295+
liberty_files.push_back(liberty_file);
309296
continue;
310297
}
311298
if (args[argidx] == "-dont_use" && argidx+1 < args.size()) {
@@ -319,10 +306,20 @@ struct ClockgatePass : public Pass {
319306
break;
320307
}
321308

322-
if (!liberty_file.empty())
309+
if (!liberty_files.empty()) {
310+
LibertyMergedCells merged;
311+
for (auto path : liberty_files) {
312+
std::ifstream f;
313+
f.open(path.c_str());
314+
if (f.fail())
315+
log_cmd_error("Can't open liberty file `%s': %s\n", path.c_str(), strerror(errno));
316+
LibertyParser p(f);
317+
merged.merge(p);
318+
f.close();
319+
}
323320
std::tie(pos_icg_desc, neg_icg_desc) =
324-
find_icgs(liberty_file, dont_use_cells);
325-
else {
321+
find_icgs(merged.cells, dont_use_cells);
322+
} else {
326323
for (auto pin : tie_lo_pins) {
327324
if (pos_icg_desc)
328325
pos_icg_desc->tie_lo_pins.push_back(pin);

passes/techmap/dfflibmap.cc

Lines changed: 45 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -229,22 +229,16 @@ static bool parse_pin(const LibertyAst *cell, const LibertyAst *attr, std::strin
229229
return false;
230230
}
231231

232-
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)
232+
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)
233233
{
234234
const LibertyAst *best_cell = nullptr;
235235
std::map<std::string, char> best_cell_ports;
236236
int best_cell_pins = 0;
237237
bool best_cell_noninv = false;
238238
double best_cell_area = 0;
239239

240-
if (ast->id != "library")
241-
log_error("Format error in liberty file.\n");
242-
243-
for (auto cell : ast->children)
240+
for (auto cell : cells)
244241
{
245-
if (cell->id != "cell" || cell->args.size() != 1)
246-
continue;
247-
248242
const LibertyAst *dn = cell->find("dont_use");
249243
if (dn != nullptr && dn->value == "true")
250244
continue;
@@ -355,7 +349,7 @@ static void find_cell(const LibertyAst *ast, IdString cell_type, bool clkpol, bo
355349
}
356350
}
357351

358-
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)
352+
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)
359353
{
360354
const LibertyAst *best_cell = nullptr;
361355
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,
365359

366360
log_assert(!enapol && "set/reset cell with enable is unimplemented due to lack of cells for testing");
367361

368-
if (ast->id != "library")
369-
log_error("Format error in liberty file.\n");
370-
371-
for (auto cell : ast->children)
362+
for (auto cell : cells)
372363
{
373-
if (cell->id != "cell" || cell->args.size() != 1)
374-
continue;
375-
376364
const LibertyAst *dn = cell->find("dont_use");
377365
if (dn != nullptr && dn->value == "true")
378366
continue;
@@ -561,7 +549,7 @@ struct DfflibmapPass : public Pass {
561549
log(" dfflibmap [-prepare] [-map-only] [-info] [-dont_use <cell_name>] -liberty <file> [selection]\n");
562550
log("\n");
563551
log("Map internal flip-flop cells to the flip-flop cells in the technology\n");
564-
log("library specified in the given liberty file.\n");
552+
log("library specified in the given liberty files.\n");
565553
log("\n");
566554
log("This pass may add inverters as needed. Therefore it is recommended to\n");
567555
log("first run this pass and then map the logic paths to the target technology.\n");
@@ -590,20 +578,21 @@ struct DfflibmapPass : public Pass {
590578
log_header(design, "Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n");
591579
log_push();
592580

593-
std::string liberty_file;
594581
bool prepare_mode = false;
595582
bool map_only_mode = false;
596583
bool info_mode = false;
597584

585+
std::vector<std::string> liberty_files;
598586
std::vector<std::string> dont_use_cells;
599587

600588
size_t argidx;
601589
for (argidx = 1; argidx < args.size(); argidx++)
602590
{
603591
std::string arg = args[argidx];
604592
if (arg == "-liberty" && argidx+1 < args.size()) {
605-
liberty_file = args[++argidx];
593+
std::string liberty_file = args[++argidx];
606594
rewrite_filename(liberty_file);
595+
liberty_files.push_back(liberty_file);
607596
continue;
608597
}
609598
if (arg == "-prepare") {
@@ -636,41 +625,45 @@ struct DfflibmapPass : public Pass {
636625
if (modes > 1)
637626
log_cmd_error("Only one of -prepare, -map-only, or -info options should be given!\n");
638627

639-
if (liberty_file.empty())
628+
if (liberty_files.empty())
640629
log_cmd_error("Missing `-liberty liberty_file' option!\n");
641630

642-
std::ifstream f;
643-
f.open(liberty_file.c_str());
644-
if (f.fail())
645-
log_cmd_error("Can't open liberty file `%s': %s\n", liberty_file.c_str(), strerror(errno));
646-
LibertyParser libparser(f);
647-
f.close();
648-
649-
find_cell(libparser.ast, ID($_DFF_N_), false, false, false, false, false, false, dont_use_cells);
650-
find_cell(libparser.ast, ID($_DFF_P_), true, false, false, false, false, false, dont_use_cells);
651-
652-
find_cell(libparser.ast, ID($_DFF_NN0_), false, true, false, false, false, false, dont_use_cells);
653-
find_cell(libparser.ast, ID($_DFF_NN1_), false, true, false, true, false, false, dont_use_cells);
654-
find_cell(libparser.ast, ID($_DFF_NP0_), false, true, true, false, false, false, dont_use_cells);
655-
find_cell(libparser.ast, ID($_DFF_NP1_), false, true, true, true, false, false, dont_use_cells);
656-
find_cell(libparser.ast, ID($_DFF_PN0_), true, true, false, false, false, false, dont_use_cells);
657-
find_cell(libparser.ast, ID($_DFF_PN1_), true, true, false, true, false, false, dont_use_cells);
658-
find_cell(libparser.ast, ID($_DFF_PP0_), true, true, true, false, false, false, dont_use_cells);
659-
find_cell(libparser.ast, ID($_DFF_PP1_), true, true, true, true, false, false, dont_use_cells);
660-
661-
find_cell(libparser.ast, ID($_DFFE_NN_), false, false, false, false, true, false, dont_use_cells);
662-
find_cell(libparser.ast, ID($_DFFE_NP_), false, false, false, false, true, true, dont_use_cells);
663-
find_cell(libparser.ast, ID($_DFFE_PN_), true, false, false, false, true, false, dont_use_cells);
664-
find_cell(libparser.ast, ID($_DFFE_PP_), true, false, false, false, true, true, dont_use_cells);
665-
666-
find_cell_sr(libparser.ast, ID($_DFFSR_NNN_), false, false, false, false, false, dont_use_cells);
667-
find_cell_sr(libparser.ast, ID($_DFFSR_NNP_), false, false, true, false, false, dont_use_cells);
668-
find_cell_sr(libparser.ast, ID($_DFFSR_NPN_), false, true, false, false, false, dont_use_cells);
669-
find_cell_sr(libparser.ast, ID($_DFFSR_NPP_), false, true, true, false, false, dont_use_cells);
670-
find_cell_sr(libparser.ast, ID($_DFFSR_PNN_), true, false, false, false, false, dont_use_cells);
671-
find_cell_sr(libparser.ast, ID($_DFFSR_PNP_), true, false, true, false, false, dont_use_cells);
672-
find_cell_sr(libparser.ast, ID($_DFFSR_PPN_), true, true, false, false, false, dont_use_cells);
673-
find_cell_sr(libparser.ast, ID($_DFFSR_PPP_), true, true, true, false, false, dont_use_cells);
631+
LibertyMergedCells merged;
632+
for (auto path : liberty_files) {
633+
std::ifstream f;
634+
f.open(path.c_str());
635+
if (f.fail())
636+
log_cmd_error("Can't open liberty file `%s': %s\n", path.c_str(), strerror(errno));
637+
LibertyParser p(f);
638+
merged.merge(p);
639+
f.close();
640+
}
641+
642+
find_cell(merged.cells, ID($_DFF_N_), false, false, false, false, false, false, dont_use_cells);
643+
find_cell(merged.cells, ID($_DFF_P_), true, false, false, false, false, false, dont_use_cells);
644+
645+
find_cell(merged.cells, ID($_DFF_NN0_), false, true, false, false, false, false, dont_use_cells);
646+
find_cell(merged.cells, ID($_DFF_NN1_), false, true, false, true, false, false, dont_use_cells);
647+
find_cell(merged.cells, ID($_DFF_NP0_), false, true, true, false, false, false, dont_use_cells);
648+
find_cell(merged.cells, ID($_DFF_NP1_), false, true, true, true, false, false, dont_use_cells);
649+
find_cell(merged.cells, ID($_DFF_PN0_), true, true, false, false, false, false, dont_use_cells);
650+
find_cell(merged.cells, ID($_DFF_PN1_), true, true, false, true, false, false, dont_use_cells);
651+
find_cell(merged.cells, ID($_DFF_PP0_), true, true, true, false, false, false, dont_use_cells);
652+
find_cell(merged.cells, ID($_DFF_PP1_), true, true, true, true, false, false, dont_use_cells);
653+
654+
find_cell(merged.cells, ID($_DFFE_NN_), false, false, false, false, true, false, dont_use_cells);
655+
find_cell(merged.cells, ID($_DFFE_NP_), false, false, false, false, true, true, dont_use_cells);
656+
find_cell(merged.cells, ID($_DFFE_PN_), true, false, false, false, true, false, dont_use_cells);
657+
find_cell(merged.cells, ID($_DFFE_PP_), true, false, false, false, true, true, dont_use_cells);
658+
659+
find_cell_sr(merged.cells, ID($_DFFSR_NNN_), false, false, false, false, false, dont_use_cells);
660+
find_cell_sr(merged.cells, ID($_DFFSR_NNP_), false, false, true, false, false, dont_use_cells);
661+
find_cell_sr(merged.cells, ID($_DFFSR_NPN_), false, true, false, false, false, dont_use_cells);
662+
find_cell_sr(merged.cells, ID($_DFFSR_NPP_), false, true, true, false, false, dont_use_cells);
663+
find_cell_sr(merged.cells, ID($_DFFSR_PNN_), true, false, false, false, false, dont_use_cells);
664+
find_cell_sr(merged.cells, ID($_DFFSR_PNP_), true, false, true, false, false, dont_use_cells);
665+
find_cell_sr(merged.cells, ID($_DFFSR_PPN_), true, true, false, false, false, dont_use_cells);
666+
find_cell_sr(merged.cells, ID($_DFFSR_PPP_), true, true, true, false, false, dont_use_cells);
674667

675668
log(" final dff cell mappings:\n");
676669
logmap_all();

passes/techmap/libparse.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -503,12 +503,12 @@ LibertyAst *LibertyParser::parse()
503503

504504
#ifndef FILTERLIB
505505

506-
void LibertyParser::error()
506+
void LibertyParser::error() const
507507
{
508508
log_error("Syntax error in liberty file on line %d.\n", line);
509509
}
510510

511-
void LibertyParser::error(const std::string &str)
511+
void LibertyParser::error(const std::string &str) const
512512
{
513513
std::stringstream ss;
514514
ss << "Syntax error in liberty file on line " << line << ".\n";
@@ -518,13 +518,13 @@ void LibertyParser::error(const std::string &str)
518518

519519
#else
520520

521-
void LibertyParser::error()
521+
void LibertyParser::error() const
522522
{
523523
fprintf(stderr, "Syntax error in liberty file on line %d.\n", line);
524524
exit(1);
525525
}
526526

527-
void LibertyParser::error(const std::string &str)
527+
void LibertyParser::error(const std::string &str) const
528528
{
529529
std::stringstream ss;
530530
ss << "Syntax error in liberty file on line " << line << ".\n";

passes/techmap/libparse.h

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,10 @@ namespace Yosys
8686
bool eval(dict<std::string, bool>& values);
8787
};
8888

89+
class LibertyMergedCells;
8990
class LibertyParser
9091
{
92+
friend class LibertyMergedCells;
9193
private:
9294
std::istream &f;
9395
int line;
@@ -98,17 +100,46 @@ namespace Yosys
98100
anything else is a single character.
99101
*/
100102
int lexer(std::string &str);
101-
103+
102104
LibertyAst *parse();
103-
void error();
104-
void error(const std::string &str);
105+
void error() const;
106+
void error(const std::string &str) const;
105107

106108
public:
107109
const LibertyAst *ast;
108110

109111
LibertyParser(std::istream &f) : f(f), line(1), ast(parse()) {}
110112
~LibertyParser() { if (ast) delete ast; }
111113
};
114+
115+
class LibertyMergedCells
116+
{
117+
std::vector<const LibertyAst *> asts;
118+
119+
public:
120+
std::vector<const LibertyAst *> cells;
121+
void merge(LibertyParser &parser)
122+
{
123+
if (parser.ast) {
124+
const LibertyAst *ast = parser.ast;
125+
asts.push_back(ast);
126+
// The parser no longer owns its top level ast, but we do.
127+
// sketchy zone
128+
parser.ast = nullptr;
129+
if (ast->id != "library")
130+
parser.error("Top level entity isn't \"library\".\n");
131+
for (const LibertyAst *cell : ast->children)
132+
if (cell->id == "cell" && cell->args.size() == 1)
133+
cells.push_back(cell);
134+
}
135+
}
136+
~LibertyMergedCells()
137+
{
138+
for (auto ast : asts)
139+
delete ast;
140+
}
141+
};
142+
112143
}
113144

114145
#endif

tests/techmap/clockgate.ys

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,49 @@ select -module dffe_11 -assert-count 0 t:\$_NOT_
235235

236236
#------------------------------------------------------------------------------
237237

238+
# test multiple liberty files to behave the same way
239+
design -load before
240+
clockgate -liberty clockgate_pos.lib -liberty clockgate_neg.lib
241+
242+
# rising edge ICGs
243+
select -module dffe_00 -assert-count 0 t:\\pos_small
244+
select -module dffe_01 -assert-count 0 t:\\pos_small
245+
246+
select -module dffe_10 -assert-count 1 t:\\pos_small
247+
select -module dffe_11 -assert-count 1 t:\\pos_small
248+
249+
# falling edge ICGs
250+
select -module dffe_00 -assert-count 1 t:\\neg_small
251+
select -module dffe_01 -assert-count 1 t:\\neg_small
252+
253+
select -module dffe_10 -assert-count 0 t:\\neg_small
254+
select -module dffe_11 -assert-count 0 t:\\neg_small
255+
256+
# and nothing else
257+
select -module dffe_00 -assert-count 0 t:\\pos_big
258+
select -module dffe_01 -assert-count 0 t:\\pos_big
259+
select -module dffe_10 -assert-count 0 t:\\pos_big
260+
select -module dffe_11 -assert-count 0 t:\\pos_big
261+
select -module dffe_00 -assert-count 0 t:\\pos_small_tielo
262+
select -module dffe_01 -assert-count 0 t:\\pos_small_tielo
263+
select -module dffe_10 -assert-count 0 t:\\pos_small_tielo
264+
select -module dffe_11 -assert-count 0 t:\\pos_small_tielo
265+
select -module dffe_00 -assert-count 0 t:\\neg_big
266+
select -module dffe_01 -assert-count 0 t:\\neg_big
267+
select -module dffe_10 -assert-count 0 t:\\neg_big
268+
select -module dffe_11 -assert-count 0 t:\\neg_big
269+
select -module dffe_00 -assert-count 0 t:\\neg_small_tielo
270+
select -module dffe_01 -assert-count 0 t:\\neg_small_tielo
271+
select -module dffe_10 -assert-count 0 t:\\neg_small_tielo
272+
select -module dffe_11 -assert-count 0 t:\\neg_small_tielo
273+
274+
# if necessary, EN is inverted, since the given ICG
275+
# is assumed to have an active-high EN
276+
select -module dffe_10 -assert-count 1 t:\$_NOT_
277+
select -module dffe_11 -assert-count 0 t:\$_NOT_
278+
279+
#------------------------------------------------------------------------------
280+
238281
design -load before
239282
clockgate -liberty clockgate.lib -dont_use pos_small -dont_use neg_small
240283

0 commit comments

Comments
 (0)