mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	Merge pull request #4797 from YosysHQ/emil/multiple-liberty
Allow multiple -liberty args in dfflibmap and clockgate
This commit is contained in:
		
						commit
						3b8e8ee012
					
				
					 10 changed files with 323 additions and 77 deletions
				
			
		| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			@ -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");
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -291,18 +277,23 @@ 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]);
 | 
			
		||||
| 
						 | 
				
			
			@ -310,13 +301,25 @@ struct ClockgatePass : public Pass {
 | 
			
		|||
			}
 | 
			
		||||
			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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -229,7 +229,7 @@ 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;
 | 
			
		||||
| 
						 | 
				
			
			@ -237,14 +237,8 @@ static void find_cell(const LibertyAst *ast, IdString cell_type, bool clkpol, bo
 | 
			
		|||
	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;
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			@ -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");
 | 
			
		||||
| 
						 | 
				
			
			@ -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_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;
 | 
			
		||||
| 
						 | 
				
			
			@ -602,8 +590,9 @@ struct DfflibmapPass : public Pass {
 | 
			
		|||
		{
 | 
			
		||||
			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") {
 | 
			
		||||
| 
						 | 
				
			
			@ -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();
 | 
			
		||||
		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(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(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(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(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(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(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(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);
 | 
			
		||||
		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();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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";
 | 
			
		||||
| 
						 | 
				
			
			@ -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";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			@ -98,10 +100,10 @@ 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;
 | 
			
		||||
| 
						 | 
				
			
			@ -109,6 +111,35 @@ namespace Yosys
 | 
			
		|||
		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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
clockgate -liberty clockgate.lib -dont_use pos_small -dont_use neg_small
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										55
									
								
								tests/techmap/clockgate_neg.lib
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								tests/techmap/clockgate_neg.lib
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										55
									
								
								tests/techmap/clockgate_pos.lib
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								tests/techmap/clockgate_pos.lib
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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-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
 | 
			
		||||
dfflibmap -liberty dfflibmap.lib -dont_use *ffn
 | 
			
		||||
clean
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										23
									
								
								tests/techmap/dfflibmap_dffn.lib
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								tests/techmap/dfflibmap_dffn.lib
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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";
 | 
			
		||||
    } 
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								tests/techmap/dfflibmap_dffsr.lib
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								tests/techmap/dfflibmap_dffsr.lib
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue