mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-30 19:22:31 +00:00 
			
		
		
		
	initial import
This commit is contained in:
		
						commit
						7764d0ba1d
					
				
					 481 changed files with 54634 additions and 0 deletions
				
			
		
							
								
								
									
										10
									
								
								passes/dfflibmap/Makefile.inc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								passes/dfflibmap/Makefile.inc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| 
 | ||||
| OBJS += passes/dfflibmap/dfflibmap.o | ||||
| OBJS += passes/dfflibmap/libparse.o | ||||
| 
 | ||||
| TARGETS += filterlib | ||||
| GENFILES += passes/dfflibmap/filterlib.o | ||||
| 
 | ||||
| filterlib: passes/dfflibmap/filterlib.o | ||||
| 	$(CXX) -o filterlib $(LDFLAGS) $^ $(LDLIBS) | ||||
| 
 | ||||
							
								
								
									
										326
									
								
								passes/dfflibmap/dfflibmap.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										326
									
								
								passes/dfflibmap/dfflibmap.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,326 @@ | |||
| /*
 | ||||
|  *  yosys -- Yosys Open SYnthesis Suite | ||||
|  * | ||||
|  *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> | ||||
|  *   | ||||
|  *  Permission to use, copy, modify, and/or distribute this software for any | ||||
|  *  purpose with or without fee is hereby granted, provided that the above | ||||
|  *  copyright notice and this permission notice appear in all copies. | ||||
|  *   | ||||
|  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "kernel/register.h" | ||||
| #include "kernel/log.h" | ||||
| #include "libparse.h" | ||||
| #include <string.h> | ||||
| 
 | ||||
| using namespace PASS_DFFLIBMAP; | ||||
| 
 | ||||
| struct cell_mapping { | ||||
| 	std::string cell_name; | ||||
| 	std::map<std::string, char> ports; | ||||
| }; | ||||
| static std::map<std::string, cell_mapping> cell_mappings; | ||||
| 
 | ||||
| static void logmap(std::string dff) | ||||
| { | ||||
| 	if (cell_mappings.count(dff) == 0) { | ||||
| 		log("    unmapped dff cell: %s\n", dff.c_str()); | ||||
| 	} else { | ||||
| 		log("    %s %s(", cell_mappings[dff].cell_name.c_str(), dff.substr(1).c_str()); | ||||
| 		bool first = true; | ||||
| 		for (auto &port : cell_mappings[dff].ports) { | ||||
| 			char arg[3] = { port.second, 0, 0 }; | ||||
| 			if ('a' <= arg[0] && arg[0] <= 'z') | ||||
| 				arg[1] = arg[0] - ('a' - 'A'), arg[0] = '~'; | ||||
| 			log("%s.%s(%s)", first ? "" : ", ", port.first.c_str(), arg); | ||||
| 			first = false; | ||||
| 		} | ||||
| 		log(");\n"); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void logmap_all() | ||||
| { | ||||
| 	logmap("$_DFF_N_"); | ||||
| 	logmap("$_DFF_P_"); | ||||
| 	logmap("$_DFF_NN0_"); | ||||
| 	logmap("$_DFF_NN1_"); | ||||
| 	logmap("$_DFF_NP0_"); | ||||
| 	logmap("$_DFF_NP1_"); | ||||
| 	logmap("$_DFF_PN0_"); | ||||
| 	logmap("$_DFF_PN1_"); | ||||
| 	logmap("$_DFF_PP0_"); | ||||
| 	logmap("$_DFF_PP1_"); | ||||
| } | ||||
| 
 | ||||
| static bool parse_pin(LibertyAst *cell, LibertyAst *attr, std::string &pin_name, bool &pin_pol) | ||||
| { | ||||
| 	if (cell == NULL || attr == NULL || attr->value.empty()) | ||||
| 		return false; | ||||
| 	 | ||||
| 	std::string value = attr->value; | ||||
| 
 | ||||
| 	for (size_t pos = value.find_first_of("\" \t"); pos != std::string::npos; pos = value.find_first_of("\" \t")) | ||||
| 		value.erase(pos, 1); | ||||
| 
 | ||||
| 	if (value[value.size()-1] == '\'') { | ||||
| 		pin_name = value.substr(0, value.size()-1); | ||||
| 		pin_pol = false; | ||||
| 	} else { | ||||
| 		pin_name = value; | ||||
| 		pin_pol = true; | ||||
| 	} | ||||
| 
 | ||||
| 	for (auto child : cell->children) | ||||
| 		if (child->id == "pin" && child->args.size() == 1 && child->args[0] == pin_name) | ||||
| 			return true; | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval) | ||||
| { | ||||
| 	LibertyAst *best_cell = NULL; | ||||
| 	std::map<std::string, char> best_cell_ports; | ||||
| 	int best_cell_pins = 0; | ||||
| 
 | ||||
| 	if (ast->id != "library") | ||||
| 		log_error("Format error in liberty file.\n"); | ||||
| 
 | ||||
| 	for (auto cell : ast->children) | ||||
| 	{ | ||||
| 		if (cell->id != "cell" || cell->args.size() != 1) | ||||
| 			continue; | ||||
| 
 | ||||
| 		LibertyAst *ff = cell->find("ff"); | ||||
| 		if (ff == NULL) | ||||
| 			continue; | ||||
| 
 | ||||
| 		std::string cell_clk_pin, cell_rst_pin, cell_next_pin; | ||||
| 		bool cell_clk_pol, cell_rst_pol, cell_next_pol; | ||||
| 
 | ||||
| 		if (!parse_pin(cell, ff->find("clocked_on"), cell_clk_pin, cell_clk_pol) || cell_clk_pol != clkpol) | ||||
| 			continue; | ||||
| 		if (!parse_pin(cell, ff->find("next_state"), cell_next_pin, cell_next_pol)) | ||||
| 			continue; | ||||
| 		if (has_reset && rstval == false) { | ||||
| 			if (!parse_pin(cell, ff->find("clear"), cell_rst_pin, cell_rst_pol) || cell_rst_pol != rstpol) | ||||
| 				continue; | ||||
| 		} | ||||
| 		if (has_reset && rstval == true) { | ||||
| 			if (!parse_pin(cell, ff->find("preset"), cell_rst_pin, cell_rst_pol) || cell_rst_pol != rstpol) | ||||
| 				continue; | ||||
| 		} | ||||
| 
 | ||||
| 		std::map<std::string, char> this_cell_ports; | ||||
| 		this_cell_ports[cell_clk_pin] = 'C'; | ||||
| 		if (has_reset) | ||||
| 			this_cell_ports[cell_rst_pin] = 'R'; | ||||
| 		this_cell_ports[cell_next_pin] = 'D'; | ||||
| 
 | ||||
| 		int num_pins = 0; | ||||
| 		bool found_output = false; | ||||
| 		for (auto pin : cell->children) | ||||
| 		{ | ||||
| 			if (pin->id != "pin" || pin->args.size() != 1) | ||||
| 				continue; | ||||
| 
 | ||||
| 			LibertyAst *dir = pin->find("direction"); | ||||
| 			if (dir == NULL || dir->value == "internal") | ||||
| 				continue; | ||||
| 			num_pins++; | ||||
| 
 | ||||
| 			if (dir->value == "input" && this_cell_ports.count(pin->args[0]) == 0) | ||||
| 				goto continue_cell_loop; | ||||
| 
 | ||||
| 			LibertyAst *func = pin->find("function"); | ||||
| 			if (dir->value == "output" && func != NULL) { | ||||
| 				std::string value = func->value; | ||||
| 				for (size_t pos = value.find_first_of("\" \t"); pos != std::string::npos; pos = value.find_first_of("\" \t")) | ||||
| 					value.erase(pos, 1); | ||||
| 				if ((cell_next_pol == true && value == ff->args[0]) || (cell_next_pol == false && value == ff->args[1])) { | ||||
| 					this_cell_ports[pin->args[0]] = 'Q'; | ||||
| 					found_output = true; | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			if (this_cell_ports.count(pin->args[0]) == 0) | ||||
| 				this_cell_ports[pin->args[0]] = 0; | ||||
| 		} | ||||
| 
 | ||||
| 		if (!found_output || (best_cell != NULL && num_pins > best_cell_pins)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		best_cell = cell; | ||||
| 		best_cell_pins = num_pins; | ||||
| 		best_cell_ports.swap(this_cell_ports); | ||||
| 	continue_cell_loop:; | ||||
| 	} | ||||
| 
 | ||||
| 	if (best_cell != NULL) { | ||||
| 		log("  cell %s is a direct match for cell type %s.\n", best_cell->args[0].c_str(), cell_type.substr(1).c_str()); | ||||
| 		cell_mappings[cell_type].cell_name = 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) { | ||||
| 		if (inv.find(it.second) == 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, to = it.first; | ||||
| 		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 dfflibmap(RTLIL::Module *module) | ||||
| { | ||||
| 	log("Mapping DFF cells in module `%s':\n", module->name.c_str()); | ||||
| 
 | ||||
| 	std::vector<RTLIL::Cell*> cell_list; | ||||
| 	for (auto &it : module->cells) { | ||||
| 		if (cell_mappings.count(it.second->type) > 0) | ||||
| 			cell_list.push_back(it.second); | ||||
| 	} | ||||
| 
 | ||||
| 	std::map<std::string, int> stats; | ||||
| 	for (auto cell : cell_list) { | ||||
| 		cell_mapping &cm = cell_mappings[cell->type]; | ||||
| 		RTLIL::Cell *new_cell = new RTLIL::Cell; | ||||
| 		new_cell->name = cell->name; | ||||
| 		new_cell->type = "\\" + cm.cell_name; | ||||
| 		for (auto &port : cm.ports) { | ||||
| 			RTLIL::SigSpec sig; | ||||
| 			if ('A' <= port.second && port.second <= 'Z') { | ||||
| 				sig = cell->connections[std::string("\\") + port.second]; | ||||
| 			} else | ||||
| 			if ('a' <= port.second && port.second <= 'z') { | ||||
| 				sig = cell->connections[std::string("\\") + char(port.second - ('a' - 'A'))]; | ||||
| 				RTLIL::Cell *inv_cell = new RTLIL::Cell; | ||||
| 				RTLIL::Wire *inv_wire = new RTLIL::Wire; | ||||
| 				inv_cell->name = stringf("$dfflibmap$inv$%d", RTLIL::autoidx); | ||||
| 				inv_wire->name = stringf("$dfflibmap$sig$%d", RTLIL::autoidx++); | ||||
| 				inv_cell->type = "$_INV_"; | ||||
| 				inv_cell->connections[port.second == 'q' ? "\\Y" : "\\A"] = sig; | ||||
| 				sig = RTLIL::SigSpec(inv_wire); | ||||
| 				inv_cell->connections[port.second == 'q' ? "\\A" : "\\Y"] = sig; | ||||
| 				module->cells[inv_cell->name] = inv_cell; | ||||
| 				module->wires[inv_wire->name] = inv_wire; | ||||
| 			} | ||||
| 			new_cell->connections["\\" + port.first] = sig; | ||||
| 		} | ||||
| 		stats[stringf("  mapped %%d %s cells to %s cells.\n", cell->type.c_str(), new_cell->type.c_str())]++; | ||||
| 		module->cells[cell->name] = new_cell; | ||||
| 		delete cell; | ||||
| 	} | ||||
| 
 | ||||
| 	for (auto &stat: stats) | ||||
| 		log(stat.first.c_str(), stat.second); | ||||
| } | ||||
| 
 | ||||
| struct DfflibmapPass : public Pass { | ||||
| 	DfflibmapPass() : Pass("dfflibmap") { } | ||||
| 	virtual void execute(std::vector<std::string> args, RTLIL::Design *design) | ||||
| 	{ | ||||
| 		log_header("Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n"); | ||||
| 
 | ||||
| 		std::string liberty_file; | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) | ||||
| 		{ | ||||
| 			std::string arg = args[argidx]; | ||||
| 			if (arg == "-liberty" && argidx+1 < args.size()) { | ||||
| 				liberty_file = args[++argidx]; | ||||
| 				continue; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
| 
 | ||||
| 		if (liberty_file.empty()) | ||||
| 			log_cmd_error("Missing `-liberty liberty_file' option!\n"); | ||||
| 
 | ||||
| 		FILE *f = fopen(liberty_file.c_str(), "r"); | ||||
| 		if (f == NULL) | ||||
| 			log_cmd_error("Can't open liberty file `%s': %s\n", liberty_file.c_str(), strerror(errno)); | ||||
| 		LibertyParer libparser(f); | ||||
| 		fclose(f); | ||||
| 
 | ||||
| 		find_cell(libparser.ast, "$_DFF_N_", false, false, false, false); | ||||
| 		find_cell(libparser.ast, "$_DFF_P_", true, false, false, false); | ||||
| 		find_cell(libparser.ast, "$_DFF_NN0_", false, true, false, false); | ||||
| 		find_cell(libparser.ast, "$_DFF_NN1_", false, true, false, true); | ||||
| 		find_cell(libparser.ast, "$_DFF_NP0_", false, true, true, false); | ||||
| 		find_cell(libparser.ast, "$_DFF_NP1_", false, true, true, true); | ||||
| 		find_cell(libparser.ast, "$_DFF_PN0_", true, true, false, false); | ||||
| 		find_cell(libparser.ast, "$_DFF_PN1_", true, true, false, true); | ||||
| 		find_cell(libparser.ast, "$_DFF_PP0_", true, true, true, false); | ||||
| 		find_cell(libparser.ast, "$_DFF_PP1_", true, true, true, true); | ||||
| 
 | ||||
| 		bool keep_running = true; | ||||
| 		while (keep_running) { | ||||
| 			keep_running = false; | ||||
| 			keep_running |= expand_cellmap("$_DFF_*_", "C"); | ||||
| 			keep_running |= expand_cellmap("$_DFF_*??_", "C"); | ||||
| 			keep_running |= expand_cellmap("$_DFF_?*?_", "R"); | ||||
| 			keep_running |= expand_cellmap("$_DFF_??*_", "DQ"); | ||||
| 		} | ||||
|   | ||||
|  		log("  final dff cell mappings:\n"); | ||||
|  		logmap_all(); | ||||
| 
 | ||||
| 		for (auto &it : design->modules) | ||||
| 			dfflibmap(it.second); | ||||
| 
 | ||||
| 		cell_mappings.clear(); | ||||
| 	} | ||||
| } DfflibmapPass; | ||||
|   | ||||
							
								
								
									
										4
									
								
								passes/dfflibmap/filterlib.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								passes/dfflibmap/filterlib.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | |||
| 
 | ||||
| #define FILTERLIB | ||||
| #include "libparse.cc" | ||||
| 
 | ||||
							
								
								
									
										629
									
								
								passes/dfflibmap/libparse.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										629
									
								
								passes/dfflibmap/libparse.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,629 @@ | |||
| /*
 | ||||
|  *  yosys -- Yosys Open SYnthesis Suite | ||||
|  * | ||||
|  *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> | ||||
|  *   | ||||
|  *  Permission to use, copy, modify, and/or distribute this software for any | ||||
|  *  purpose with or without fee is hereby granted, provided that the above | ||||
|  *  copyright notice and this permission notice appear in all copies. | ||||
|  *   | ||||
|  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "libparse.h" | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| #ifndef FILTERLIB | ||||
| #include "kernel/log.h" | ||||
| #endif | ||||
| 
 | ||||
| using namespace PASS_DFFLIBMAP; | ||||
| 
 | ||||
| std::set<std::string> LibertyAst::blacklist; | ||||
| std::set<std::string> LibertyAst::whitelist; | ||||
| 
 | ||||
| LibertyAst::~LibertyAst() | ||||
| { | ||||
| 	for (auto child : children) | ||||
| 		delete child; | ||||
| 	children.clear(); | ||||
| } | ||||
| 
 | ||||
| LibertyAst *LibertyAst::find(std::string name) | ||||
| { | ||||
| 	if (this == NULL) | ||||
| 		return NULL; | ||||
| 	for (auto child : children) | ||||
| 		if (child->id == name) | ||||
| 			return child; | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| void LibertyAst::dump(FILE *f, std::string indent, std::string path, bool path_ok) | ||||
| { | ||||
| 	if (whitelist.count(path + "/*") > 0) | ||||
| 		path_ok = true; | ||||
| 
 | ||||
| 	path += "/" + id; | ||||
| 
 | ||||
| 	if (blacklist.count(id) > 0 || blacklist.count(path) > 0) | ||||
| 		return; | ||||
| 	if (whitelist.size() > 0 && whitelist.count(id) == 0 && whitelist.count(path) == 0 && !path_ok) { | ||||
| 		fprintf(stderr, "Automatically added to blacklist: %s\n", path.c_str()); | ||||
| 		blacklist.insert(id); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	fprintf(f, "%s%s", indent.c_str(), id.c_str()); | ||||
| 	if (!args.empty()) { | ||||
| 		for (size_t i = 0; i < args.size(); i++) | ||||
| 			fprintf(f, "%s%s", i > 0 ? ", " : "(", args[i].c_str()); | ||||
| 		fprintf(f, ")"); | ||||
| 	} | ||||
| 	if (!value.empty()) | ||||
| 		fprintf(f, " : %s", value.c_str()); | ||||
| 	if (!children.empty()) { | ||||
| 		fprintf(f, " {\n"); | ||||
| 		for (size_t i = 0; i < children.size(); i++) | ||||
| 			children[i]->dump(f, indent + "  ", path, path_ok); | ||||
| 		fprintf(f, "%s}\n", indent.c_str()); | ||||
| 	} else | ||||
| 		fprintf(f, " ;\n"); | ||||
| } | ||||
| 
 | ||||
| int LibertyParer::lexer(std::string &str) | ||||
| { | ||||
| 	int c; | ||||
| 
 | ||||
| 	do { | ||||
| 		c = fgetc(f); | ||||
| 	} while (c == ' ' || c == '\t' || c == '\r'); | ||||
| 
 | ||||
| 	if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '.') { | ||||
| 		str = c; | ||||
| 		while (1) { | ||||
| 			c = fgetc(f); | ||||
| 			if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '.') | ||||
| 				str += c; | ||||
| 			else | ||||
| 				break; | ||||
| 		} | ||||
| 		ungetc(c, f); | ||||
| 		// fprintf(stderr, "LEX: identifier >>%s<<\n", str.c_str());
 | ||||
| 		return 'v'; | ||||
| 	} | ||||
| 
 | ||||
| 	if (c == '"') { | ||||
| 		str = c; | ||||
| 		while (1) { | ||||
| 			c = fgetc(f); | ||||
| 			if (c == '\n') | ||||
| 				line++; | ||||
| 			str += c; | ||||
| 			if (c == '"') | ||||
| 				break; | ||||
| 		} | ||||
| 		// fprintf(stderr, "LEX: string >>%s<<\n", str.c_str());
 | ||||
| 		return 'v'; | ||||
| 	} | ||||
| 
 | ||||
| 	if (c == '/') { | ||||
| 		c = fgetc(f); | ||||
| 		if (c == '*') { | ||||
| 			int last_c = 0; | ||||
| 			while (c > 0 && (last_c != '*' || c != '/')) { | ||||
| 				last_c = c; | ||||
| 				c = fgetc(f); | ||||
| 				if (c == '\n') | ||||
| 					line++; | ||||
| 			} | ||||
| 			return lexer(str); | ||||
| 		} | ||||
| 		ungetc(c, f); | ||||
| 		// fprintf(stderr, "LEX: char >>/<<\n");
 | ||||
| 		return '/'; | ||||
| 	} | ||||
| 
 | ||||
| 	if (c == '\\') { | ||||
| 		c = fgetc(f); | ||||
| 		if (c == '\r') | ||||
| 			c = fgetc(f); | ||||
| 		if (c == '\n') | ||||
| 			return lexer(str); | ||||
| 		ungetc(c, f); | ||||
| 		return '\\'; | ||||
| 	} | ||||
| 
 | ||||
| 	if (c == '\n') { | ||||
| 		line++; | ||||
| 		return ';'; | ||||
| 	} | ||||
| 
 | ||||
| 	// if (c >= 32 && c < 255)
 | ||||
| 	// 	fprintf(stderr, "LEX: char >>%c<<\n", c);
 | ||||
| 	// else
 | ||||
| 	// 	fprintf(stderr, "LEX: char %d\n", c);
 | ||||
| 	return c; | ||||
| } | ||||
| 
 | ||||
| LibertyAst *LibertyParer::parse() | ||||
| { | ||||
| 	std::string str; | ||||
| 
 | ||||
| 	int tok = lexer(str); | ||||
| 
 | ||||
| 	while (tok == ';') | ||||
| 		tok = lexer(str); | ||||
| 
 | ||||
| 	if (tok == '}' || tok < 0) | ||||
| 		return NULL; | ||||
| 	 | ||||
| 	if (tok != 'v') | ||||
| 		error(); | ||||
| 
 | ||||
| 	LibertyAst *ast = new LibertyAst; | ||||
| 	ast->id = str; | ||||
| 
 | ||||
| 	while (1) | ||||
| 	{ | ||||
| 		tok = lexer(str); | ||||
| 
 | ||||
| 		if (tok == ';') | ||||
| 			break; | ||||
| 
 | ||||
| 		if (tok == ':' && ast->value.empty()) { | ||||
| 			tok = lexer(ast->value); | ||||
| 			if (tok != 'v') | ||||
| 				error(); | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		if (tok == '(') { | ||||
| 			while (1) { | ||||
| 				std::string arg; | ||||
| 				tok = lexer(arg); | ||||
| 				if (tok == ',') | ||||
| 					continue; | ||||
| 				if (tok == ')') | ||||
| 					break; | ||||
| 				if (tok != 'v') | ||||
| 					error(); | ||||
| 				ast->args.push_back(arg); | ||||
| 			} | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		if (tok == '{') { | ||||
| 			while (1) { | ||||
| 				LibertyAst *child = parse(); | ||||
| 				if (child == NULL) | ||||
| 					break; | ||||
| 				ast->children.push_back(child); | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		error(); | ||||
| 	} | ||||
| 
 | ||||
| 	return ast; | ||||
| } | ||||
| 
 | ||||
| #ifndef FILTERLIB | ||||
| 
 | ||||
| void LibertyParer::error() | ||||
| { | ||||
| 	log_error("Syntax error in line %d.\n", line); | ||||
| } | ||||
| 
 | ||||
| #else | ||||
| 
 | ||||
| void LibertyParer::error() | ||||
| { | ||||
| 	fprintf(stderr, "Syntax error in line %d.\n", line); | ||||
| 	exit(1); | ||||
| } | ||||
| 
 | ||||
| /**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/ | ||||
| 
 | ||||
| // This is to not confuse the VIM syntax highlighting
 | ||||
| #define CHECK_VAL_OPEN ( | ||||
| #define CHECK_VAL_CLOSE ) | ||||
| 
 | ||||
| #define CHECK(result, check)                                         \ | ||||
|    CHECK_VAL_OPEN{                                                   \ | ||||
|      auto _R = (result);                                             \ | ||||
|      if (!(_R check)) {                                              \ | ||||
|        fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n",       \ | ||||
|                #result, (long int)_R, #check, __FILE__, __LINE__);   \ | ||||
|        abort();                                                      \ | ||||
|      }                                                               \ | ||||
|      _R;                                                             \ | ||||
|    }CHECK_VAL_CLOSE | ||||
| 
 | ||||
| #define CHECK_NV(result, check)                                      \ | ||||
|    do {                                                              \ | ||||
|      auto _R = (result);                                             \ | ||||
|      if (!(_R check)) {                                              \ | ||||
|        fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n",       \ | ||||
|                #result, (long int)_R, #check, __FILE__, __LINE__);   \ | ||||
|        abort();                                                      \ | ||||
|      }                                                               \ | ||||
|    } while(0) | ||||
| 
 | ||||
| #define CHECK_COND(result)                                           \ | ||||
|    do {                                                              \ | ||||
|      if (!(result)) {                                                \ | ||||
|        fprintf(stderr, "Error from '%s' in %s:%d.\n",                \ | ||||
|                #result, __FILE__, __LINE__);                         \ | ||||
|        abort();                                                      \ | ||||
|      }                                                               \ | ||||
|    } while(0) | ||||
| 
 | ||||
| /**** END: http://svn.clifford.at/tools/trunk/examples/check.h ****/ | ||||
| 
 | ||||
| std::string func2vl(std::string str) | ||||
| { | ||||
| 	for (size_t pos = str.find_first_of("\" \t"); pos != std::string::npos; pos = str.find_first_of("\" \t")) { | ||||
| 		char c_left = pos > 0 ? str[pos-1] : ' '; | ||||
| 		char c_right = pos+1 < str.size() ? str[pos+1] : ' '; | ||||
| 		if (std::string("\" \t*+").find(c_left) != std::string::npos) | ||||
| 			str.erase(pos, 1); | ||||
| 		else if (std::string("\" \t*+").find(c_right) != std::string::npos) | ||||
| 			str.erase(pos, 1); | ||||
| 		else | ||||
| 			str[pos] = '*'; | ||||
| 	} | ||||
| 
 | ||||
| 	std::vector<size_t> group_start; | ||||
| 	for (size_t pos = 0; pos < str.size(); pos++) { | ||||
| 		if (str[pos] == '(') | ||||
| 			group_start.push_back(pos); | ||||
| 		if (str[pos] == ')' && group_start.size() > 0) { | ||||
| 			if (pos+1 < str.size() && str[pos+1] == '\'') { | ||||
| 				std::string group = str.substr(group_start.back(), pos-group_start.back()+1); | ||||
| 				str[group_start.back()] = '~'; | ||||
| 				str.replace(group_start.back()+1, group.size(), group); | ||||
| 				pos++; | ||||
| 			} | ||||
| 			group_start.pop_back(); | ||||
| 		} | ||||
| 		if (str[pos] == '\'' && pos > 0) { | ||||
| 			size_t start = str.find_last_of("()'*+^&| ", pos-1)+1; | ||||
| 			std::string group = str.substr(start, pos-start); | ||||
| 			str[start] = '~'; | ||||
| 			str.replace(start+1, group.size(), group); | ||||
| 		} | ||||
| 		if (str[pos] == '*') | ||||
| 			str[pos] = '&'; | ||||
| 		if (str[pos] == '+') | ||||
| 			str[pos] = '|'; | ||||
| 	} | ||||
| 
 | ||||
| 	return str; | ||||
| } | ||||
| 
 | ||||
| void event2vl(LibertyAst *ast, std::string &edge, std::string &expr) | ||||
| { | ||||
| 	edge.clear(); | ||||
| 	expr.clear(); | ||||
| 
 | ||||
| 	if (ast != NULL) { | ||||
| 		expr = func2vl(ast->value); | ||||
| 		if (expr.size() > 0 && expr[0] == '~') | ||||
| 			edge = "negedge " + expr.substr(1); | ||||
| 		else | ||||
| 			edge = "posedge " + expr; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void clear_preset_var(std::string var, std::string type) | ||||
| { | ||||
| 	if (type.find('L') != std::string::npos) { | ||||
| 		printf("      %s <= 0;\n", var.c_str()); | ||||
| 		return; | ||||
| 	} | ||||
| 	if (type.find('H') != std::string::npos) { | ||||
| 		printf("      %s <= 1;\n", var.c_str()); | ||||
| 		return; | ||||
| 	} | ||||
| 	if (type.find('T') != std::string::npos) { | ||||
| 		printf("      %s <= ~%s;\n", var.c_str(), var.c_str()); | ||||
| 		return; | ||||
| 	} | ||||
| 	if (type.find('X') != std::string::npos) { | ||||
| 		printf("      %s <= 'bx;\n", var.c_str()); | ||||
| 		return; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void gen_verilogsim_cell(LibertyAst *ast) | ||||
| { | ||||
| 	if (ast->find("statetable") != NULL) | ||||
| 		return; | ||||
| 
 | ||||
| 	CHECK_NV(ast->args.size(), == 1); | ||||
| 	printf("module %s (", ast->args[0].c_str()); | ||||
| 	bool first = true; | ||||
| 	for (auto child : ast->children) { | ||||
| 		if (child->id != "pin") | ||||
| 			continue; | ||||
| 		CHECK_NV(child->args.size(), == 1); | ||||
| 		printf("%s%s", first ? "" : ", ", child->args[0].c_str()); | ||||
| 		first = false; | ||||
| 	} | ||||
| 	printf(");\n"); | ||||
| 
 | ||||
| 	for (auto child : ast->children) { | ||||
| 		if (child->id != "ff" && child->id != "latch") | ||||
| 			continue; | ||||
| 		printf("  reg "); | ||||
| 		first = true; | ||||
| 		for (auto arg : child->args) { | ||||
| 			printf("%s%s", first ? "" : ", ", arg.c_str()); | ||||
| 			first = false; | ||||
| 		} | ||||
| 		printf(";\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	for (auto child : ast->children) { | ||||
| 		if (child->id != "pin") | ||||
| 			continue; | ||||
| 		CHECK_NV(child->args.size(), == 1); | ||||
| 		LibertyAst *dir = CHECK(child->find("direction"), != NULL); | ||||
| 		LibertyAst *func = child->find("function"); | ||||
| 		printf("  %s %s;\n", dir->value.c_str(), child->args[0].c_str()); | ||||
| 		if (func != NULL) | ||||
| 			printf("  assign %s = %s; // %s\n", child->args[0].c_str(), func2vl(func->value).c_str(), func->value.c_str()); | ||||
| 	} | ||||
| 
 | ||||
| 	for (auto child : ast->children) | ||||
| 	{ | ||||
| 		if (child->id != "ff" || child->args.size() != 2) | ||||
| 			continue; | ||||
| 
 | ||||
| 		std::string iq_var = child->args[0]; | ||||
| 		std::string iqn_var = child->args[1]; | ||||
| 
 | ||||
| 		std::string clock_edge, clock_expr; | ||||
| 		event2vl(child->find("clocked_on"), clock_edge, clock_expr); | ||||
| 
 | ||||
| 		std::string clear_edge, clear_expr; | ||||
| 		event2vl(child->find("clear"), clear_edge, clear_expr); | ||||
| 
 | ||||
| 		std::string preset_edge, preset_expr; | ||||
| 		event2vl(child->find("preset"), preset_edge, preset_expr); | ||||
| 
 | ||||
| 		std::string edge = ""; | ||||
| 		if (!clock_edge.empty()) | ||||
| 			edge += (edge.empty() ? "" : ", ") + clock_edge; | ||||
| 		if (!clear_edge.empty()) | ||||
| 			edge += (edge.empty() ? "" : ", ") + clear_edge; | ||||
| 		if (!preset_edge.empty()) | ||||
| 			edge += (edge.empty() ? "" : ", ") + preset_edge; | ||||
| 
 | ||||
| 		if (edge.empty()) | ||||
| 			continue; | ||||
| 
 | ||||
| 		printf("  always @(%s) begin\n", edge.c_str()); | ||||
| 
 | ||||
| 		const char *else_prefix = ""; | ||||
| 		if (!clear_expr.empty() && !preset_expr.empty()) { | ||||
| 			printf("    %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str()); | ||||
| 			clear_preset_var(iq_var, CHECK(child->find("clear_preset_var1"), != NULL)->value); | ||||
| 			clear_preset_var(iqn_var, CHECK(child->find("clear_preset_var2"), != NULL)->value); | ||||
| 			printf("    end\n"); | ||||
| 			else_prefix = "else "; | ||||
| 		} | ||||
| 		if (!clear_expr.empty()) { | ||||
| 			printf("    %sif (%s) begin\n", else_prefix, clear_expr.c_str()); | ||||
| 			printf("      %s <= 0;\n", iq_var.c_str()); | ||||
| 			printf("      %s <= 1;\n", iqn_var.c_str()); | ||||
| 			printf("    end\n"); | ||||
| 			else_prefix = "else "; | ||||
| 		} | ||||
| 		if (!preset_expr.empty()) { | ||||
| 			printf("    %sif (%s) begin\n", else_prefix, preset_expr.c_str()); | ||||
| 			printf("      %s <= 1;\n", iq_var.c_str()); | ||||
| 			printf("      %s <= 0;\n", iqn_var.c_str()); | ||||
| 			printf("    end\n"); | ||||
| 			else_prefix = "else "; | ||||
| 		} | ||||
| 		if (*else_prefix) | ||||
| 			printf("    %sbegin\n", else_prefix); | ||||
| 		std::string expr = CHECK(child->find("next_state"), != NULL)->value; | ||||
| 		printf("      // %s\n", expr.c_str()); | ||||
| 		printf("      %s <= %s;\n", iq_var.c_str(), func2vl(expr).c_str()); | ||||
| 		printf("      %s <= ~(%s);\n", iqn_var.c_str(), func2vl(expr).c_str()); | ||||
| 		if (*else_prefix) | ||||
| 			printf("    end\n"); | ||||
| 
 | ||||
| 		printf("  end\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	for (auto child : ast->children) | ||||
| 	{ | ||||
| 		if (child->id != "latch" || child->args.size() != 2) | ||||
| 			continue; | ||||
| 
 | ||||
| 		std::string iq_var = child->args[0]; | ||||
| 		std::string iqn_var = child->args[1]; | ||||
| 
 | ||||
| 		std::string enable_edge, enable_expr; | ||||
| 		event2vl(child->find("enable"), enable_edge, enable_expr); | ||||
| 
 | ||||
| 		std::string clear_edge, clear_expr; | ||||
| 		event2vl(child->find("clear"), clear_edge, clear_expr); | ||||
| 
 | ||||
| 		std::string preset_edge, preset_expr; | ||||
| 		event2vl(child->find("preset"), preset_edge, preset_expr); | ||||
| 
 | ||||
| 		printf("  always @* begin\n"); | ||||
| 
 | ||||
| 		const char *else_prefix = ""; | ||||
| 		if (!clear_expr.empty() && !preset_expr.empty()) { | ||||
| 			printf("    %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str()); | ||||
| 			clear_preset_var(iq_var, CHECK(child->find("clear_preset_var1"), != NULL)->value); | ||||
| 			clear_preset_var(iqn_var, CHECK(child->find("clear_preset_var2"), != NULL)->value); | ||||
| 			printf("    end\n"); | ||||
| 			else_prefix = "else "; | ||||
| 		} | ||||
| 		if (!clear_expr.empty()) { | ||||
| 			printf("    %sif (%s) begin\n", else_prefix, clear_expr.c_str()); | ||||
| 			printf("      %s <= 0;\n", iq_var.c_str()); | ||||
| 			printf("      %s <= 1;\n", iqn_var.c_str()); | ||||
| 			printf("    end\n"); | ||||
| 			else_prefix = "else "; | ||||
| 		} | ||||
| 		if (!preset_expr.empty()) { | ||||
| 			printf("    %sif (%s) begin\n", else_prefix, preset_expr.c_str()); | ||||
| 			printf("      %s <= 1;\n", iq_var.c_str()); | ||||
| 			printf("      %s <= 0;\n", iqn_var.c_str()); | ||||
| 			printf("    end\n"); | ||||
| 			else_prefix = "else "; | ||||
| 		} | ||||
| 		if (!enable_expr.empty()) { | ||||
| 			printf("    %sif (%s) begin\n", else_prefix, enable_expr.c_str()); | ||||
| 			std::string expr = CHECK(child->find("data_in"), != NULL)->value; | ||||
| 			printf("      %s <= %s;\n", iq_var.c_str(), func2vl(expr).c_str()); | ||||
| 			printf("      %s <= ~(%s);\n", iqn_var.c_str(), func2vl(expr).c_str()); | ||||
| 			printf("    end\n"); | ||||
| 			else_prefix = "else "; | ||||
| 		} | ||||
| 
 | ||||
| 		printf("  end\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	printf("endmodule\n"); | ||||
| } | ||||
| 
 | ||||
| void gen_verilogsim(LibertyAst *ast) | ||||
| { | ||||
| 	CHECK_COND(ast->id == "library"); | ||||
| 
 | ||||
| 	for (auto child : ast->children) | ||||
| 		if (child->id == "cell" && !child->find("dont_use")) | ||||
| 			gen_verilogsim_cell(child); | ||||
| } | ||||
| 
 | ||||
| void usage() | ||||
| { | ||||
| 	fprintf(stderr, "Usage: filterlib [rules-file [liberty-file]]\n"); | ||||
| 	fprintf(stderr, "   or: filterlib -verilogsim [liberty-file]\n"); | ||||
| 	exit(1); | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
| 	bool flag_verilogsim = false; | ||||
| 
 | ||||
| 	if (argc > 3) | ||||
| 		usage(); | ||||
| 
 | ||||
| 	if (argc > 1) | ||||
| 	{ | ||||
| 		if (!strcmp(argv[1], "-verilogsim")) | ||||
| 			flag_verilogsim = true; | ||||
| 		if (!strcmp(argv[1], "-") || !strcmp(argv[1], "-verilogsim")) | ||||
| 		{ | ||||
| 			LibertyAst::whitelist.insert("/library"); | ||||
| 			LibertyAst::whitelist.insert("/library/cell"); | ||||
| 			LibertyAst::whitelist.insert("/library/cell/area"); | ||||
| 			LibertyAst::whitelist.insert("/library/cell/cell_footprint"); | ||||
| 			LibertyAst::whitelist.insert("/library/cell/dont_touch"); | ||||
| 			LibertyAst::whitelist.insert("/library/cell/dont_use"); | ||||
| 			LibertyAst::whitelist.insert("/library/cell/ff"); | ||||
| 			LibertyAst::whitelist.insert("/library/cell/ff/*"); | ||||
| 			LibertyAst::whitelist.insert("/library/cell/latch"); | ||||
| 			LibertyAst::whitelist.insert("/library/cell/latch/*"); | ||||
| 			LibertyAst::whitelist.insert("/library/cell/pin"); | ||||
| 			LibertyAst::whitelist.insert("/library/cell/pin/clock"); | ||||
| 			LibertyAst::whitelist.insert("/library/cell/pin/direction"); | ||||
| 			LibertyAst::whitelist.insert("/library/cell/pin/driver_type"); | ||||
| 			LibertyAst::whitelist.insert("/library/cell/pin/function"); | ||||
| 			LibertyAst::whitelist.insert("/library/cell/pin_opposite"); | ||||
| 			LibertyAst::whitelist.insert("/library/cell/pin/state_function"); | ||||
| 			LibertyAst::whitelist.insert("/library/cell/pin/three_state"); | ||||
| 			LibertyAst::whitelist.insert("/library/cell/statetable"); | ||||
| 			LibertyAst::whitelist.insert("/library/cell/statetable/*"); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			FILE *f = fopen(argv[1], "r"); | ||||
| 			if (f == NULL) { | ||||
| 				fprintf(stderr, "Can't open rules file `%s'.\n", argv[1]); | ||||
| 				usage(); | ||||
| 			} | ||||
| 
 | ||||
| 			char buffer[1024]; | ||||
| 			while (fgets(buffer, 1024, f) != NULL) | ||||
| 			{ | ||||
| 				char mode = 0; | ||||
| 				std::string id; | ||||
| 				for (char *p = buffer; *p; p++) | ||||
| 				{ | ||||
| 					if (*p == '-' || *p == '+') { | ||||
| 						if (mode != 0) | ||||
| 							goto syntax_error; | ||||
| 						mode = *p; | ||||
| 						continue; | ||||
| 					} | ||||
| 					if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n' || *p == '#') { | ||||
| 						if (!id.empty()) { | ||||
| 							if (mode == '-') | ||||
| 								LibertyAst::blacklist.insert(id); | ||||
| 							else | ||||
| 							if (mode == '+') | ||||
| 								LibertyAst::whitelist.insert(id); | ||||
| 							else | ||||
| 								goto syntax_error; | ||||
| 						} | ||||
| 						id.clear(); | ||||
| 						if (*p == '#') | ||||
| 							break; | ||||
| 						continue; | ||||
| 					} | ||||
| 					id += *p; | ||||
| 					continue; | ||||
| 
 | ||||
| 				syntax_error: | ||||
| 					fprintf(stderr, "Syntax error in rules file:\n%s", buffer); | ||||
| 					exit(1); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	FILE *f = stdin; | ||||
| 	if (argc == 3) { | ||||
| 		f = fopen(argv[2], "r"); | ||||
| 		if (f == NULL) { | ||||
| 			fprintf(stderr, "Can't open liberty file `%s'.\n", argv[2]); | ||||
| 			usage(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	LibertyParer parser(f); | ||||
| 	if (parser.ast) { | ||||
| 		if (flag_verilogsim) | ||||
| 			gen_verilogsim(parser.ast); | ||||
| 		else | ||||
| 			parser.ast->dump(stdout); | ||||
| 	} | ||||
| 
 | ||||
| 	if (argc == 3) | ||||
| 		fclose(f); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
							
								
								
									
										56
									
								
								passes/dfflibmap/libparse.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								passes/dfflibmap/libparse.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,56 @@ | |||
| /*
 | ||||
|  *  yosys -- Yosys Open SYnthesis Suite | ||||
|  * | ||||
|  *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> | ||||
|  *   | ||||
|  *  Permission to use, copy, modify, and/or distribute this software for any | ||||
|  *  purpose with or without fee is hereby granted, provided that the above | ||||
|  *  copyright notice and this permission notice appear in all copies. | ||||
|  *   | ||||
|  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #ifndef LIBPARSE_H | ||||
| #define LIBPARSE_H | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <string> | ||||
| #include <vector> | ||||
| #include <set> | ||||
| 
 | ||||
| namespace PASS_DFFLIBMAP | ||||
| { | ||||
| 	struct LibertyAst | ||||
| 	{ | ||||
| 		std::string id, value; | ||||
| 		std::vector<std::string> args; | ||||
| 		std::vector<LibertyAst*> children; | ||||
| 		~LibertyAst(); | ||||
| 		LibertyAst *find(std::string name); | ||||
| 		void dump(FILE *f, std::string indent = "", std::string path = "", bool path_ok = false); | ||||
| 		static std::set<std::string> blacklist; | ||||
| 		static std::set<std::string> whitelist; | ||||
| 	}; | ||||
| 
 | ||||
| 	struct LibertyParer | ||||
| 	{ | ||||
| 		FILE *f; | ||||
| 		int line; | ||||
| 		LibertyAst *ast; | ||||
| 		LibertyParer(FILE *f) : f(f), line(1), ast(parse()) {} | ||||
| 		~LibertyParer() { if (ast) delete ast; } | ||||
| 		int lexer(std::string &str); | ||||
| 		LibertyAst *parse(); | ||||
| 		void error(); | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue