mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 11:42:30 +00:00 
			
		
		
		
	dfflibmap: Refactor to use dfflegalize internally.
This commit is contained in:
		
							parent
							
								
									68babb2ae4
								
							
						
					
					
						commit
						7ed9d18907
					
				
					 5 changed files with 212 additions and 210 deletions
				
			
		|  | @ -115,7 +115,7 @@ static bool parse_pin(LibertyAst *cell, LibertyAst *attr, std::string &pin_name, | ||||||
| 	return false; | 	return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval, bool prepare_mode) | static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval) | ||||||
| { | { | ||||||
| 	LibertyAst *best_cell = nullptr; | 	LibertyAst *best_cell = nullptr; | ||||||
| 	std::map<std::string, char> best_cell_ports; | 	std::map<std::string, char> best_cell_ports; | ||||||
|  | @ -222,21 +222,12 @@ static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has | ||||||
| 	if (best_cell != nullptr) { | 	if (best_cell != nullptr) { | ||||||
| 		log("  cell %s (%sinv, pins=%d, area=%.2f) is a direct match for cell type %s.\n", | 		log("  cell %s (%sinv, pins=%d, area=%.2f) is a direct match for cell type %s.\n", | ||||||
| 				best_cell->args[0].c_str(), best_cell_noninv ? "non" : "", best_cell_pins, best_cell_area, cell_type.c_str()); | 				best_cell->args[0].c_str(), best_cell_noninv ? "non" : "", best_cell_pins, best_cell_area, cell_type.c_str()); | ||||||
| 		if (prepare_mode) { |  | ||||||
| 			cell_mappings[cell_type].cell_name = cell_type; |  | ||||||
| 			cell_mappings[cell_type].ports["C"] = 'C'; |  | ||||||
| 			if (has_reset) |  | ||||||
| 				cell_mappings[cell_type].ports["R"] = 'R'; |  | ||||||
| 			cell_mappings[cell_type].ports["D"] = 'D'; |  | ||||||
| 			cell_mappings[cell_type].ports["Q"] = 'Q'; |  | ||||||
| 		} else { |  | ||||||
| 		cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]); | 		cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]); | ||||||
| 		cell_mappings[cell_type].ports = best_cell_ports; | 		cell_mappings[cell_type].ports = best_cell_ports; | ||||||
| 	} | 	} | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool setpol, bool clrpol, bool prepare_mode) | static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool setpol, bool clrpol) | ||||||
| { | { | ||||||
| 	LibertyAst *best_cell = nullptr; | 	LibertyAst *best_cell = nullptr; | ||||||
| 	std::map<std::string, char> best_cell_ports; | 	std::map<std::string, char> best_cell_ports; | ||||||
|  | @ -339,141 +330,12 @@ static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool | ||||||
| 	if (best_cell != nullptr) { | 	if (best_cell != nullptr) { | ||||||
| 		log("  cell %s (%sinv, pins=%d, area=%.2f) is a direct match for cell type %s.\n", | 		log("  cell %s (%sinv, pins=%d, area=%.2f) is a direct match for cell type %s.\n", | ||||||
| 				best_cell->args[0].c_str(), best_cell_noninv ? "non" : "", best_cell_pins, best_cell_area, cell_type.c_str()); | 				best_cell->args[0].c_str(), best_cell_noninv ? "non" : "", best_cell_pins, best_cell_area, cell_type.c_str()); | ||||||
| 		if (prepare_mode) { |  | ||||||
| 			cell_mappings[cell_type].cell_name = cell_type; |  | ||||||
| 			cell_mappings[cell_type].ports["C"] = 'C'; |  | ||||||
| 			cell_mappings[cell_type].ports["S"] = 'S'; |  | ||||||
| 			cell_mappings[cell_type].ports["R"] = 'R'; |  | ||||||
| 			cell_mappings[cell_type].ports["D"] = 'D'; |  | ||||||
| 			cell_mappings[cell_type].ports["Q"] = 'Q'; |  | ||||||
| 		} else { |  | ||||||
| 		cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]); | 		cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]); | ||||||
| 		cell_mappings[cell_type].ports = best_cell_ports; | 		cell_mappings[cell_type].ports = best_cell_ports; | ||||||
| 	} | 	} | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool expand_cellmap_worker(std::string from, std::string to, std::string inv) | static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module) | ||||||
| { |  | ||||||
| 	if (cell_mappings.count(to) > 0) |  | ||||||
| 		return false; |  | ||||||
| 
 |  | ||||||
| 	log("  create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str()); |  | ||||||
| 	cell_mappings[to].cell_name = cell_mappings[from].cell_name; |  | ||||||
| 	cell_mappings[to].ports = cell_mappings[from].ports; |  | ||||||
| 
 |  | ||||||
| 	for (auto &it : cell_mappings[to].ports) { |  | ||||||
| 		char cmp_ch = it.second; |  | ||||||
| 		if ('a' <= cmp_ch && cmp_ch <= 'z') |  | ||||||
| 			cmp_ch -= 'a' - 'A'; |  | ||||||
| 		if (inv.find(cmp_ch) == std::string::npos) |  | ||||||
| 			continue; |  | ||||||
| 		if ('a' <= it.second && it.second <= 'z') |  | ||||||
| 			it.second -= 'a' - 'A'; |  | ||||||
| 		else if ('A' <= it.second && it.second <= 'Z') |  | ||||||
| 			it.second += 'a' - 'A'; |  | ||||||
| 	} |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static bool expand_cellmap(std::string pattern, std::string inv) |  | ||||||
| { |  | ||||||
| 	std::vector<std::pair<std::string, std::string>> from_to_list; |  | ||||||
| 	bool return_status = false; |  | ||||||
| 
 |  | ||||||
| 	for (auto &it : cell_mappings) { |  | ||||||
| 		std::string from = it.first.str(), to = it.first.str(); |  | ||||||
| 		if (from.size() != pattern.size()) |  | ||||||
| 			continue; |  | ||||||
| 		for (size_t i = 0; i < from.size(); i++) { |  | ||||||
| 			if (pattern[i] == '*') { |  | ||||||
| 				to[i] = from[i] == 'P' ? 'N' : |  | ||||||
| 					from[i] == 'N' ? 'P' : |  | ||||||
| 					from[i] == '1' ? '0' : |  | ||||||
| 					from[i] == '0' ? '1' : '*'; |  | ||||||
| 			} else |  | ||||||
| 			if (pattern[i] != '?' && pattern[i] != from[i]) |  | ||||||
| 				goto pattern_failed; |  | ||||||
| 		} |  | ||||||
| 		from_to_list.push_back(std::pair<std::string, std::string>(from, to)); |  | ||||||
| 	pattern_failed:; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	for (auto &it : from_to_list) |  | ||||||
| 		return_status = return_status || expand_cellmap_worker(it.first, it.second, inv); |  | ||||||
| 	return return_status; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void map_sr_to_arst(IdString from, IdString to) |  | ||||||
| { |  | ||||||
| 	if (!cell_mappings.count(from) || cell_mappings.count(to) > 0) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	char from_clk_pol = from[8]; |  | ||||||
| 	char from_set_pol = from[9]; |  | ||||||
| 	char from_clr_pol = from[10]; |  | ||||||
| 	char to_clk_pol = to[6]; |  | ||||||
| 	char to_rst_pol = to[7]; |  | ||||||
| 	char to_rst_val = to[8]; |  | ||||||
| 
 |  | ||||||
| 	log_assert(from_clk_pol == to_clk_pol); |  | ||||||
| 	log_assert(to_rst_pol == from_set_pol && to_rst_pol == from_clr_pol); |  | ||||||
| 
 |  | ||||||
| 	log("  create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str()); |  | ||||||
| 	cell_mappings[to].cell_name = cell_mappings[from].cell_name; |  | ||||||
| 	cell_mappings[to].ports = cell_mappings[from].ports; |  | ||||||
| 
 |  | ||||||
| 	for (auto &it : cell_mappings[to].ports) |  | ||||||
| 	{ |  | ||||||
| 		bool is_set_pin = it.second == 'S' || it.second == 's'; |  | ||||||
| 		bool is_clr_pin = it.second == 'R' || it.second == 'r'; |  | ||||||
| 
 |  | ||||||
| 		if (!is_set_pin && !is_clr_pin) |  | ||||||
| 			continue; |  | ||||||
| 
 |  | ||||||
| 		if ((to_rst_val == '0' && is_set_pin) || (to_rst_val == '1' && is_clr_pin)) |  | ||||||
| 		{ |  | ||||||
| 			// this is the unused set/clr pin -- deactivate it
 |  | ||||||
| 			if (is_set_pin) |  | ||||||
| 				it.second = (from_set_pol == 'P') == (it.second == 'S') ? '0' : '1'; |  | ||||||
| 			else |  | ||||||
| 				it.second = (from_clr_pol == 'P') == (it.second == 'R') ? '0' : '1'; |  | ||||||
| 		} |  | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
| 			// this is the used set/clr pin -- rename it to 'reset'
 |  | ||||||
| 			if (it.second == 'S') |  | ||||||
| 				it.second = 'R'; |  | ||||||
| 			if (it.second == 's') |  | ||||||
| 				it.second = 'r'; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void map_adff_to_dff(IdString from, IdString to) |  | ||||||
| { |  | ||||||
| 	if (!cell_mappings.count(from) || cell_mappings.count(to) > 0) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	char from_clk_pol = from[6]; |  | ||||||
| 	char from_rst_pol = from[7]; |  | ||||||
| 	char to_clk_pol = to[6]; |  | ||||||
| 
 |  | ||||||
| 	log_assert(from_clk_pol == to_clk_pol); |  | ||||||
| 
 |  | ||||||
| 	log("  create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str()); |  | ||||||
| 	cell_mappings[to].cell_name = cell_mappings[from].cell_name; |  | ||||||
| 	cell_mappings[to].ports = cell_mappings[from].ports; |  | ||||||
| 
 |  | ||||||
| 	for (auto &it : cell_mappings[to].ports) { |  | ||||||
| 		if (it.second == 'S' || it.second == 'R') |  | ||||||
| 			it.second = from_rst_pol == 'P' ? '0' : '1'; |  | ||||||
| 		if (it.second == 's' || it.second == 'r') |  | ||||||
| 			it.second = from_rst_pol == 'P' ? '1' : '0'; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare_mode) |  | ||||||
| { | { | ||||||
| 	log("Mapping DFF cells in module `%s':\n", module->name.c_str()); | 	log("Mapping DFF cells in module `%s':\n", module->name.c_str()); | ||||||
| 
 | 
 | ||||||
|  | @ -499,7 +361,7 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare | ||||||
| 		module->remove(cell); | 		module->remove(cell); | ||||||
| 
 | 
 | ||||||
| 		cell_mapping &cm = cell_mappings[cell_type]; | 		cell_mapping &cm = cell_mappings[cell_type]; | ||||||
| 		RTLIL::Cell *new_cell = module->addCell(cell_name, prepare_mode ? cm.cell_name : cm.cell_name); | 		RTLIL::Cell *new_cell = module->addCell(cell_name, cm.cell_name); | ||||||
| 
 | 
 | ||||||
| 		new_cell->set_src_attribute(src); | 		new_cell->set_src_attribute(src); | ||||||
| 
 | 
 | ||||||
|  | @ -552,7 +414,7 @@ struct DfflibmapPass : public Pass { | ||||||
| 	void help() override | 	void help() override | ||||||
| 	{ | 	{ | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("    dfflibmap [-prepare] -liberty <file> [selection]\n"); | 		log("    dfflibmap [-prepare] [-map-only] [-info] -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 file.\n"); | ||||||
|  | @ -562,15 +424,27 @@ struct DfflibmapPass : public Pass { | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("When called with -prepare, this command will convert the internal FF cells\n"); | 		log("When called with -prepare, this command will convert the internal FF cells\n"); | ||||||
| 		log("to the internal cell types that best match the cells found in the given\n"); | 		log("to the internal cell types that best match the cells found in the given\n"); | ||||||
| 		log("liberty file.\n"); | 		log("liberty file, but won't actually map them to the target cells.\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("When called with -map-only, this command will only map internal cell\n"); | ||||||
|  | 		log("types that are already of exactly the right type to match the target\n"); | ||||||
|  | 		log("cells, leaving remaining internal cells untouched.\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("When called with -info, this command will only print the target cell\n"); | ||||||
|  | 		log("list, along with their associated internal cell types, and the arguments"); | ||||||
|  | 		log("that would be passed to the dfflegalize pass.  The design will not be\n"); | ||||||
|  | 		log("changed.\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 	} | 	} | ||||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) override | 	void execute(std::vector<std::string> args, RTLIL::Design *design) override | ||||||
| 	{ | 	{ | ||||||
| 		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(); | ||||||
| 
 | 
 | ||||||
| 		std::string liberty_file; | 		std::string liberty_file; | ||||||
| 		bool prepare_mode = false; | 		bool prepare_mode = false; | ||||||
|  | 		bool map_only_mode = false; | ||||||
|  | 		bool info_mode = false; | ||||||
| 
 | 
 | ||||||
| 		size_t argidx; | 		size_t argidx; | ||||||
| 		for (argidx = 1; argidx < args.size(); argidx++) | 		for (argidx = 1; argidx < args.size(); argidx++) | ||||||
|  | @ -585,10 +459,28 @@ struct DfflibmapPass : public Pass { | ||||||
| 				prepare_mode = true; | 				prepare_mode = true; | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
|  | 			if (arg == "-map-only") { | ||||||
|  | 				map_only_mode = true; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			if (arg == "-info") { | ||||||
|  | 				info_mode = true; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 		extra_args(args, argidx, design); | 		extra_args(args, argidx, design); | ||||||
| 
 | 
 | ||||||
|  | 		int modes = 0; | ||||||
|  | 		if (prepare_mode) | ||||||
|  | 			modes++; | ||||||
|  | 		if (map_only_mode) | ||||||
|  | 			modes++; | ||||||
|  | 		if (info_mode) | ||||||
|  | 			modes++; | ||||||
|  | 		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_file.empty()) | ||||||
| 			log_cmd_error("Missing `-liberty liberty_file' option!\n"); | 			log_cmd_error("Missing `-liberty liberty_file' option!\n"); | ||||||
| 
 | 
 | ||||||
|  | @ -599,74 +491,49 @@ struct DfflibmapPass : public Pass { | ||||||
| 		LibertyParser libparser(f); | 		LibertyParser libparser(f); | ||||||
| 		f.close(); | 		f.close(); | ||||||
| 
 | 
 | ||||||
| 		find_cell(libparser.ast, ID($_DFF_N_), false, false, false, false, prepare_mode); | 		find_cell(libparser.ast, ID($_DFF_N_), false, false, false, false); | ||||||
| 		find_cell(libparser.ast, ID($_DFF_P_), true, false, false, false, prepare_mode); | 		find_cell(libparser.ast, ID($_DFF_P_), true, false, false, false); | ||||||
| 
 | 
 | ||||||
| 		find_cell(libparser.ast, ID($_DFF_NN0_), false, true, false, false, prepare_mode); | 		find_cell(libparser.ast, ID($_DFF_NN0_), false, true, false, false); | ||||||
| 		find_cell(libparser.ast, ID($_DFF_NN1_), false, true, false, true, prepare_mode); | 		find_cell(libparser.ast, ID($_DFF_NN1_), false, true, false, true); | ||||||
| 		find_cell(libparser.ast, ID($_DFF_NP0_), false, true, true, false, prepare_mode); | 		find_cell(libparser.ast, ID($_DFF_NP0_), false, true, true, false); | ||||||
| 		find_cell(libparser.ast, ID($_DFF_NP1_), false, true, true, true, prepare_mode); | 		find_cell(libparser.ast, ID($_DFF_NP1_), false, true, true, true); | ||||||
| 		find_cell(libparser.ast, ID($_DFF_PN0_), true, true, false, false, prepare_mode); | 		find_cell(libparser.ast, ID($_DFF_PN0_), true, true, false, false); | ||||||
| 		find_cell(libparser.ast, ID($_DFF_PN1_), true, true, false, true, prepare_mode); | 		find_cell(libparser.ast, ID($_DFF_PN1_), true, true, false, true); | ||||||
| 		find_cell(libparser.ast, ID($_DFF_PP0_), true, true, true, false, prepare_mode); | 		find_cell(libparser.ast, ID($_DFF_PP0_), true, true, true, false); | ||||||
| 		find_cell(libparser.ast, ID($_DFF_PP1_), true, true, true, true, prepare_mode); | 		find_cell(libparser.ast, ID($_DFF_PP1_), true, true, true, true); | ||||||
| 
 | 
 | ||||||
| 		find_cell_sr(libparser.ast, ID($_DFFSR_NNN_), false, false, false, prepare_mode); | 		find_cell_sr(libparser.ast, ID($_DFFSR_NNN_), false, false, false); | ||||||
| 		find_cell_sr(libparser.ast, ID($_DFFSR_NNP_), false, false, true, prepare_mode); | 		find_cell_sr(libparser.ast, ID($_DFFSR_NNP_), false, false, true); | ||||||
| 		find_cell_sr(libparser.ast, ID($_DFFSR_NPN_), false, true, false, prepare_mode); | 		find_cell_sr(libparser.ast, ID($_DFFSR_NPN_), false, true, false); | ||||||
| 		find_cell_sr(libparser.ast, ID($_DFFSR_NPP_), false, true, true, prepare_mode); | 		find_cell_sr(libparser.ast, ID($_DFFSR_NPP_), false, true, true); | ||||||
| 		find_cell_sr(libparser.ast, ID($_DFFSR_PNN_), true, false, false, prepare_mode); | 		find_cell_sr(libparser.ast, ID($_DFFSR_PNN_), true, false, false); | ||||||
| 		find_cell_sr(libparser.ast, ID($_DFFSR_PNP_), true, false, true, prepare_mode); | 		find_cell_sr(libparser.ast, ID($_DFFSR_PNP_), true, false, true); | ||||||
| 		find_cell_sr(libparser.ast, ID($_DFFSR_PPN_), true, true, false, prepare_mode); | 		find_cell_sr(libparser.ast, ID($_DFFSR_PPN_), true, true, false); | ||||||
| 		find_cell_sr(libparser.ast, ID($_DFFSR_PPP_), true, true, true, prepare_mode); | 		find_cell_sr(libparser.ast, ID($_DFFSR_PPP_), true, true, true); | ||||||
| 
 |  | ||||||
| 		// try to implement as many cells as possible just by inverting
 |  | ||||||
| 		// the SET and RESET pins. If necessary, implement cell types
 |  | ||||||
| 		// by inverting both D and Q. Only invert clock pins if there
 |  | ||||||
| 		// is no other way of implementing the cell.
 |  | ||||||
| 		while (1) |  | ||||||
| 		{ |  | ||||||
| 			if (expand_cellmap("$_DFF_?*?_", "R") || |  | ||||||
| 					expand_cellmap("$_DFFSR_?*?_", "S") || |  | ||||||
| 					expand_cellmap("$_DFFSR_??*_", "R")) |  | ||||||
| 				continue; |  | ||||||
| 
 |  | ||||||
| 			if (expand_cellmap("$_DFF_??*_", "DQ")) |  | ||||||
| 				continue; |  | ||||||
| 
 |  | ||||||
| 			if (expand_cellmap("$_DFF_*_", "C") || |  | ||||||
| 					expand_cellmap("$_DFF_*??_", "C") || |  | ||||||
| 					expand_cellmap("$_DFFSR_*??_", "C")) |  | ||||||
| 				continue; |  | ||||||
| 
 |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		map_sr_to_arst(ID($_DFFSR_NNN_), ID($_DFF_NN0_)); |  | ||||||
| 		map_sr_to_arst(ID($_DFFSR_NNN_), ID($_DFF_NN1_)); |  | ||||||
| 		map_sr_to_arst(ID($_DFFSR_NPP_), ID($_DFF_NP0_)); |  | ||||||
| 		map_sr_to_arst(ID($_DFFSR_NPP_), ID($_DFF_NP1_)); |  | ||||||
| 		map_sr_to_arst(ID($_DFFSR_PNN_), ID($_DFF_PN0_)); |  | ||||||
| 		map_sr_to_arst(ID($_DFFSR_PNN_), ID($_DFF_PN1_)); |  | ||||||
| 		map_sr_to_arst(ID($_DFFSR_PPP_), ID($_DFF_PP0_)); |  | ||||||
| 		map_sr_to_arst(ID($_DFFSR_PPP_), ID($_DFF_PP1_)); |  | ||||||
| 
 |  | ||||||
| 		map_adff_to_dff(ID($_DFF_NN0_), ID($_DFF_N_)); |  | ||||||
| 		map_adff_to_dff(ID($_DFF_NN1_), ID($_DFF_N_)); |  | ||||||
| 		map_adff_to_dff(ID($_DFF_NP0_), ID($_DFF_N_)); |  | ||||||
| 		map_adff_to_dff(ID($_DFF_NP1_), ID($_DFF_N_)); |  | ||||||
| 		map_adff_to_dff(ID($_DFF_PN0_), ID($_DFF_P_)); |  | ||||||
| 		map_adff_to_dff(ID($_DFF_PN1_), ID($_DFF_P_)); |  | ||||||
| 		map_adff_to_dff(ID($_DFF_PP0_), ID($_DFF_P_)); |  | ||||||
| 		map_adff_to_dff(ID($_DFF_PP1_), ID($_DFF_P_)); |  | ||||||
| 
 | 
 | ||||||
| 		log("  final dff cell mappings:\n"); | 		log("  final dff cell mappings:\n"); | ||||||
| 		logmap_all(); | 		logmap_all(); | ||||||
| 
 | 
 | ||||||
|  | 		if (!map_only_mode) { | ||||||
|  | 			std::string dfflegalize_cmd = "dfflegalize"; | ||||||
|  | 			for (auto it : cell_mappings) | ||||||
|  | 				dfflegalize_cmd += stringf(" -cell %s 01", it.first.c_str()); | ||||||
|  | 			dfflegalize_cmd += " t:$_DFF* t:$_SDFF*"; | ||||||
|  | 			if (info_mode) { | ||||||
|  | 				log("dfflegalize command line: %s\n", dfflegalize_cmd.c_str()); | ||||||
|  | 			} else { | ||||||
|  | 				Pass::call(design, dfflegalize_cmd); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (!prepare_mode && !info_mode) { | ||||||
| 			for (auto module : design->selected_modules()) | 			for (auto module : design->selected_modules()) | ||||||
| 				if (!module->get_blackbox_attribute()) | 				if (!module->get_blackbox_attribute()) | ||||||
| 				dfflibmap(design, module, prepare_mode); | 					dfflibmap(design, module); | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
|  | 		log_pop(); | ||||||
| 		cell_mappings.clear(); | 		cell_mappings.clear(); | ||||||
| 	} | 	} | ||||||
| } DfflibmapPass; | } DfflibmapPass; | ||||||
|  |  | ||||||
|  | @ -5,6 +5,6 @@ for x in *.lib; do | ||||||
| 	echo "Running $x.." | 	echo "Running $x.." | ||||||
|     echo "read_verilog small.v" > test.ys |     echo "read_verilog small.v" > test.ys | ||||||
|     echo "synth -top small" >> test.ys |     echo "synth -top small" >> test.ys | ||||||
|     echo "dfflibmap -liberty ${x}" >> test.ys |     echo "dfflibmap -info -liberty ${x}" >> test.ys | ||||||
| 	../../yosys -ql ${x%.lib}.log -s test.ys | 	../../yosys -ql ${x%.lib}.log -s test.ys | ||||||
| done | done | ||||||
|  |  | ||||||
							
								
								
									
										22
									
								
								tests/techmap/dfflibmap-sim.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								tests/techmap/dfflibmap-sim.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | ||||||
|  | module dffn(input CLK, D, output reg Q, output QN); | ||||||
|  | 
 | ||||||
|  | always @(negedge CLK) | ||||||
|  | 	Q <= D; | ||||||
|  | 
 | ||||||
|  | assign QN = ~Q; | ||||||
|  | 
 | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  | module dffsr(input CLK, D, CLEAR, PRESET, output reg Q, output QN); | ||||||
|  | 
 | ||||||
|  | always @(posedge CLK, posedge CLEAR, posedge PRESET) | ||||||
|  | 	if (CLEAR) | ||||||
|  | 		Q <= 0; | ||||||
|  | 	else if (PRESET) | ||||||
|  | 		Q <= 1; | ||||||
|  | 	else | ||||||
|  | 		Q <= D; | ||||||
|  | 
 | ||||||
|  | assign QN = ~Q; | ||||||
|  | 
 | ||||||
|  | endmodule | ||||||
							
								
								
									
										55
									
								
								tests/techmap/dfflibmap.lib
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								tests/techmap/dfflibmap.lib
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,55 @@ | ||||||
|  | library(test) { | ||||||
|  |   /* D-type flip-flop with asynchronous reset and preset */ | ||||||
|  |   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"; | ||||||
|  |     }  | ||||||
|  |   } | ||||||
|  |   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"; | ||||||
|  |     }  | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										58
									
								
								tests/techmap/dfflibmap.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								tests/techmap/dfflibmap.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,58 @@ | ||||||
|  | read_verilog -icells <<EOT | ||||||
|  | 
 | ||||||
|  | module top(input C, D, S, R, output [9:0] Q); | ||||||
|  | 
 | ||||||
|  | $_DFF_P_ ff0 (.C(C), .D(D), .Q(Q[0])); | ||||||
|  | $_DFF_PP0_ ff1 (.C(C), .D(D), .R(R), .Q(Q[1])); | ||||||
|  | $_DFF_PP1_ ff2 (.C(C), .D(D), .R(R), .Q(Q[2])); | ||||||
|  | $_DFFSR_PPP_ ff3 (.C(C), .D(D), .R(R), .S(S), .Q(Q[3])); | ||||||
|  | $_DFFSR_NNN_ ff4 (.C(C), .D(D), .R(R), .S(S), .Q(Q[4])); | ||||||
|  | 
 | ||||||
|  | assign Q[9:5] = ~Q[4:0]; | ||||||
|  | 
 | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  | EOT | ||||||
|  | 
 | ||||||
|  | simplemap | ||||||
|  | 
 | ||||||
|  | design -save orig | ||||||
|  | 
 | ||||||
|  | #equiv_opt -map dfflibmap-sim.v -assert -multiclock dfflibmap -liberty dfflibmap.lib | ||||||
|  | #equiv_opt -map dfflibmap-sim.v -assert -multiclock dfflibmap -prepare -liberty dfflibmap.lib | ||||||
|  | dfflibmap -prepare -liberty dfflibmap.lib | ||||||
|  | equiv_opt -map dfflibmap-sim.v -assert -multiclock dfflibmap -map-only -liberty dfflibmap.lib | ||||||
|  | 
 | ||||||
|  | design -load orig | ||||||
|  | dfflibmap -liberty dfflibmap.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 -prepare -liberty dfflibmap.lib | ||||||
|  | 
 | ||||||
|  | select -assert-count 9 t:$_NOT_ | ||||||
|  | select -assert-count 1 t:$_DFF_N_ | ||||||
|  | select -assert-count 4 t:$_DFFSR_PPP_ | ||||||
|  | select -assert-none t:$_DFF_N_ t:$_DFFSR_PPP_ t:$_NOT_ %% %n t:* %i | ||||||
|  | 
 | ||||||
|  | design -load orig | ||||||
|  | dfflibmap -map-only -liberty dfflibmap.lib | ||||||
|  | 
 | ||||||
|  | select -assert-count 5 t:$_NOT_ | ||||||
|  | select -assert-count 0 t:dffn | ||||||
|  | select -assert-count 1 t:dffsr | ||||||
|  | 
 | ||||||
|  | design -load orig | ||||||
|  | dfflibmap -prepare -liberty dfflibmap.lib | ||||||
|  | dfflibmap -map-only -liberty dfflibmap.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 | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue