mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-29 18:52: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; | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| 	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) { | ||||
| 		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()); | ||||
| 		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].ports = best_cell_ports; | ||||
| 		} | ||||
| 		cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]); | ||||
| 		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; | ||||
| 	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) { | ||||
| 		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()); | ||||
| 		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].ports = best_cell_ports; | ||||
| 		} | ||||
| 		cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]); | ||||
| 		cell_mappings[cell_type].ports = best_cell_ports; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static bool expand_cellmap_worker(std::string from, std::string to, std::string inv) | ||||
| { | ||||
| 	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) | ||||
| static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module) | ||||
| { | ||||
| 	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); | ||||
| 
 | ||||
| 		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); | ||||
| 
 | ||||
|  | @ -552,7 +414,7 @@ struct DfflibmapPass : public Pass { | |||
| 	void help() override | ||||
| 	{ | ||||
| 		log("\n"); | ||||
| 		log("    dfflibmap [-prepare] -liberty <file> [selection]\n"); | ||||
| 		log("    dfflibmap [-prepare] [-map-only] [-info] -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"); | ||||
|  | @ -562,15 +424,27 @@ struct DfflibmapPass : public Pass { | |||
| 		log("\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("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"); | ||||
| 	} | ||||
| 	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_push(); | ||||
| 
 | ||||
| 		std::string liberty_file; | ||||
| 		bool prepare_mode = false; | ||||
| 		bool map_only_mode = false; | ||||
| 		bool info_mode = false; | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) | ||||
|  | @ -585,10 +459,28 @@ struct DfflibmapPass : public Pass { | |||
| 				prepare_mode = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-map-only") { | ||||
| 				map_only_mode = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-info") { | ||||
| 				info_mode = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		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()) | ||||
| 			log_cmd_error("Missing `-liberty liberty_file' option!\n"); | ||||
| 
 | ||||
|  | @ -599,74 +491,49 @@ struct DfflibmapPass : public Pass { | |||
| 		LibertyParser libparser(f); | ||||
| 		f.close(); | ||||
| 
 | ||||
| 		find_cell(libparser.ast, ID($_DFF_N_), false, false, false, false, prepare_mode); | ||||
| 		find_cell(libparser.ast, ID($_DFF_P_), true, 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); | ||||
| 
 | ||||
| 		find_cell(libparser.ast, ID($_DFF_NN0_), false, true, false, false, prepare_mode); | ||||
| 		find_cell(libparser.ast, ID($_DFF_NN1_), false, true, false, true, prepare_mode); | ||||
| 		find_cell(libparser.ast, ID($_DFF_NP0_), false, true, true, false, prepare_mode); | ||||
| 		find_cell(libparser.ast, ID($_DFF_NP1_), false, true, true, true, prepare_mode); | ||||
| 		find_cell(libparser.ast, ID($_DFF_PN0_), true, true, false, false, prepare_mode); | ||||
| 		find_cell(libparser.ast, ID($_DFF_PN1_), true, true, false, true, prepare_mode); | ||||
| 		find_cell(libparser.ast, ID($_DFF_PP0_), true, true, true, false, prepare_mode); | ||||
| 		find_cell(libparser.ast, ID($_DFF_PP1_), true, true, true, true, prepare_mode); | ||||
| 		find_cell(libparser.ast, ID($_DFF_NN0_), false, true, false, false); | ||||
| 		find_cell(libparser.ast, ID($_DFF_NN1_), false, true, false, true); | ||||
| 		find_cell(libparser.ast, ID($_DFF_NP0_), false, true, true, false); | ||||
| 		find_cell(libparser.ast, ID($_DFF_NP1_), false, true, true, true); | ||||
| 		find_cell(libparser.ast, ID($_DFF_PN0_), true, true, false, false); | ||||
| 		find_cell(libparser.ast, ID($_DFF_PN1_), true, true, false, true); | ||||
| 		find_cell(libparser.ast, ID($_DFF_PP0_), true, true, true, false); | ||||
| 		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_NNP_), false, false, true, prepare_mode); | ||||
| 		find_cell_sr(libparser.ast, ID($_DFFSR_NPN_), false, true, false, prepare_mode); | ||||
| 		find_cell_sr(libparser.ast, ID($_DFFSR_NPP_), false, true, true, prepare_mode); | ||||
| 		find_cell_sr(libparser.ast, ID($_DFFSR_PNN_), true, false, false, prepare_mode); | ||||
| 		find_cell_sr(libparser.ast, ID($_DFFSR_PNP_), true, false, true, prepare_mode); | ||||
| 		find_cell_sr(libparser.ast, ID($_DFFSR_PPN_), true, true, false, prepare_mode); | ||||
| 		find_cell_sr(libparser.ast, ID($_DFFSR_PPP_), true, true, true, prepare_mode); | ||||
| 
 | ||||
| 		// 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_)); | ||||
| 		find_cell_sr(libparser.ast, ID($_DFFSR_NNN_), false, false, false); | ||||
| 		find_cell_sr(libparser.ast, ID($_DFFSR_NNP_), false, false, true); | ||||
| 		find_cell_sr(libparser.ast, ID($_DFFSR_NPN_), false, true, false); | ||||
| 		find_cell_sr(libparser.ast, ID($_DFFSR_NPP_), false, true, true); | ||||
| 		find_cell_sr(libparser.ast, ID($_DFFSR_PNN_), true, false, false); | ||||
| 		find_cell_sr(libparser.ast, ID($_DFFSR_PNP_), true, false, true); | ||||
| 		find_cell_sr(libparser.ast, ID($_DFFSR_PPN_), true, true, false); | ||||
| 		find_cell_sr(libparser.ast, ID($_DFFSR_PPP_), true, true, true); | ||||
| 
 | ||||
| 		log("  final dff cell mappings:\n"); | ||||
| 		logmap_all(); | ||||
| 
 | ||||
| 		for (auto module : design->selected_modules()) | ||||
| 			if (!module->get_blackbox_attribute()) | ||||
| 				dfflibmap(design, module, prepare_mode); | ||||
| 		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()) | ||||
| 				if (!module->get_blackbox_attribute()) | ||||
| 					dfflibmap(design, module); | ||||
| 		} | ||||
| 
 | ||||
| 		log_pop(); | ||||
| 		cell_mappings.clear(); | ||||
| 	} | ||||
| } DfflibmapPass; | ||||
|  |  | |||
|  | @ -5,6 +5,6 @@ for x in *.lib; do | |||
| 	echo "Running $x.." | ||||
|     echo "read_verilog small.v" > 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 | ||||
| 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