mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 11:42:30 +00:00 
			
		
		
		
	sdc: refactor more
This commit is contained in:
		
							parent
							
								
									5647bdeb2b
								
							
						
					
					
						commit
						329a3783e2
					
				
					 1 changed files with 270 additions and 204 deletions
				
			
		|  | @ -1,10 +1,8 @@ | |||
| #include "kernel/register.h" | ||||
| #include "kernel/celltypes.h" | ||||
| #include "kernel/rtlil.h" | ||||
| #include "kernel/log.h" | ||||
| #include <tcl.h> | ||||
| #include <list> | ||||
| #include <regex> | ||||
| #include <optional> | ||||
| #include <iostream> | ||||
| 
 | ||||
|  | @ -12,6 +10,76 @@ | |||
| USING_YOSYS_NAMESPACE | ||||
| PRIVATE_NAMESPACE_BEGIN | ||||
| 
 | ||||
| struct TclCall { | ||||
| 	Tcl_Interp *interp; | ||||
| 	int objc; | ||||
| 	Tcl_Obj* const* objv; | ||||
| }; | ||||
| 
 | ||||
| static int redirect_unknown(TclCall call); | ||||
| static size_t get_node_count(Tcl_Interp* interp); | ||||
| 
 | ||||
| struct BitSelection { | ||||
| 	bool all = false; | ||||
| 	std::vector<bool> bits = {}; | ||||
| 	void set_all() { | ||||
| 		bits.clear(); | ||||
| 		all = true; | ||||
| 	} | ||||
| 	void clear() { | ||||
| 		bits.clear(); | ||||
| 		all = false; | ||||
| 	} | ||||
| 	void set(size_t idx) { | ||||
| 		if (all) | ||||
| 			return; | ||||
| 		if (idx >= bits.size()) | ||||
| 			bits.resize(idx + 1); | ||||
| 		bits[idx] = true; | ||||
| 	} | ||||
| 	void merge(const BitSelection& other) { | ||||
| 		if (all) | ||||
| 			return; | ||||
| 		if (other.all) { | ||||
| 			set_all(); | ||||
| 			return; | ||||
| 		} | ||||
| 		if (other.bits.size() > bits.size()) | ||||
| 			bits.resize(other.bits.size()); | ||||
| 		for (size_t other_idx = 0; other_idx < other.bits.size(); other_idx++) { | ||||
| 			bool other_bit = other.bits[other_idx]; | ||||
| 			if (other_bit) | ||||
| 				set(other_idx); | ||||
| 		} | ||||
| 	} | ||||
| 	void dump() { | ||||
| 		if (!all) { | ||||
| 			for (size_t i = 0; i < bits.size(); i++) | ||||
| 				if (bits[i]) | ||||
| 					log("\t\t [%zu]\n", i); | ||||
| 		} else { | ||||
| 			log("\t\t FULL\n"); | ||||
| 		} | ||||
| 	} | ||||
| 	bool is_set(size_t idx) const { | ||||
| 		if (all) | ||||
| 			return true; | ||||
| 		if (idx >= bits.size()) | ||||
| 			return false; | ||||
| 		return bits[idx]; | ||||
| 	} | ||||
| 	// TODO actually use this
 | ||||
| 	void compress(size_t size) { | ||||
| 		if (bits.size() < size) | ||||
| 			return; | ||||
| 		for (size_t i = 0; i < size; i++) | ||||
| 			if (!bits[i]) | ||||
| 				return; | ||||
| 		bits.clear(); | ||||
| 		bits.shrink_to_fit(); | ||||
| 		all = true; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| struct SdcObjects { | ||||
| 	enum CollectMode { | ||||
|  | @ -28,74 +96,19 @@ struct SdcObjects { | |||
| 		// return a new graph node assuming unknown is overridden
 | ||||
| 		Graph, | ||||
| 	} value_mode; | ||||
| 	struct BitSelection { | ||||
| 		bool all = false; | ||||
| 		std::vector<bool> bits = {}; | ||||
| 		void set_all() { | ||||
| 			bits.clear(); | ||||
| 			all = true; | ||||
| 		} | ||||
| 		void clear() { | ||||
| 			bits.clear(); | ||||
| 			all = false; | ||||
| 		} | ||||
| 		void set(size_t idx) { | ||||
| 			if (all) | ||||
| 				return; | ||||
| 			if (idx >= bits.size()) | ||||
| 				bits.resize(idx + 1); | ||||
| 			bits[idx] = true; | ||||
| 		} | ||||
| 		void merge(const BitSelection& other) { | ||||
| 			if (all) | ||||
| 				return; | ||||
| 			if (other.all) { | ||||
| 				set_all(); | ||||
| 				return; | ||||
| 			} | ||||
| 			if (other.bits.size() > bits.size()) | ||||
| 				bits.resize(other.bits.size()); | ||||
| 			for (size_t other_idx = 0; other_idx < other.bits.size(); other_idx++) { | ||||
| 				bool other_bit = other.bits[other_idx]; | ||||
| 				if (other_bit) | ||||
| 					set(other_idx); | ||||
| 			} | ||||
| 		} | ||||
| 		void dump() { | ||||
| 			if (!all) { | ||||
| 				for (size_t i = 0; i < bits.size(); i++) | ||||
| 					if (bits[i]) | ||||
| 						log("\t\t [%zu]\n", i); | ||||
| 			} else { | ||||
| 				log("\t\t FULL\n"); | ||||
| 			} | ||||
| 		} | ||||
| 		bool is_set(size_t idx) { | ||||
| 			if (all) | ||||
| 				return true; | ||||
| 			if (idx >= bits.size()) | ||||
| 				return false; | ||||
| 			return bits[idx]; | ||||
| 		} | ||||
| 		// TODO actually use this
 | ||||
| 		void compress(size_t size) { | ||||
| 			if (bits.size() < size) | ||||
| 				return; | ||||
| 			for (size_t i = 0; i < size; i++) | ||||
| 				if (!bits[i]) | ||||
| 					return; | ||||
| 			bits.clear(); | ||||
| 			bits.shrink_to_fit(); | ||||
| 			all = true; | ||||
| 		} | ||||
| 	}; | ||||
| 	using CellPin = std::pair<Cell*, IdString>; | ||||
| 	std::vector<std::pair<std::string, Wire*>> design_ports; | ||||
| 	std::vector<std::pair<std::string, Cell*>> design_cells; | ||||
| 	std::vector<std::pair<std::string, CellPin>> design_pins; | ||||
| 	std::vector<std::pair<std::string, Wire*>> design_nets; | ||||
| 
 | ||||
| 	dict<std::string, BitSelection> constrained_ports; | ||||
| 	using PortPattern = std::tuple<std::string, Wire*, BitSelection>; | ||||
| 	using PinPattern = std::tuple<std::string, SdcObjects::CellPin, BitSelection>; | ||||
| 	std::vector<std::vector<PortPattern>> resolved_port_pattern_sets; | ||||
| 	std::vector<std::vector<PinPattern>> resolved_pin_pattern_sets; | ||||
| 	// TODO
 | ||||
| 
 | ||||
| 	dict<std::pair<std::string, Wire*>, BitSelection> constrained_ports; | ||||
| 	pool<std::pair<std::string, Cell*>> constrained_cells; | ||||
| 	dict<std::pair<std::string, CellPin>, BitSelection> constrained_pins; | ||||
| 	dict<std::pair<std::string, Wire*>, BitSelection> constrained_nets; | ||||
|  | @ -156,6 +169,30 @@ struct SdcObjects { | |||
| 		sniff_module(hierarchy, top); | ||||
| 	} | ||||
| 	~SdcObjects() = default; | ||||
| 
 | ||||
| 	template <typename T, typename U> | ||||
| 	void build_normal_result(Tcl_Interp* interp, std::vector<std::tuple<std::string, T, BitSelection>>&& resolved, U& tgt, std::function<size_t(T&)> width, Tcl_Obj*& result) { | ||||
| 		if (!result) | ||||
| 			result = Tcl_NewListObj(resolved.size(), nullptr); | ||||
| 		for (auto [name, obj, matching_bits] : resolved) { | ||||
| 			for (size_t i = 0; i < width(obj); i++) | ||||
| 				if (matching_bits.is_set(i)) { | ||||
| 					Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(name.c_str(), name.size())); | ||||
| 					break; | ||||
| 				} | ||||
| 
 | ||||
| 		} | ||||
| 		size_t node_count = get_node_count(interp); | ||||
| 		tgt.emplace_back(std::move(resolved)); | ||||
| 		log("%zu %zu\n", node_count, tgt.size()); | ||||
| 		log_assert(node_count == tgt.size()); | ||||
| 	} | ||||
| 	template <typename T> | ||||
| 	void merge_as_constrained(std::vector<std::tuple<std::string, T, BitSelection>>&& resolved) { | ||||
| 		for (auto [name, obj, matching_bits] : resolved) { | ||||
| 			merge_or_init(std::make_pair(name, obj), constrained_pins, matching_bits); | ||||
| 		} | ||||
| 	} | ||||
| 	void dump() { | ||||
| 		std::sort(design_ports.begin(), design_ports.end()); | ||||
| 		std::sort(design_cells.begin(), design_cells.end()); | ||||
|  | @ -186,7 +223,9 @@ struct SdcObjects { | |||
| 		// }
 | ||||
| 		// log("\n");
 | ||||
| 		log("Constrained ports:\n"); | ||||
| 		for (auto [name, bits] : constrained_ports) { | ||||
| 		for (auto [ref, bits] : constrained_ports) { | ||||
| 			auto [name, port] = ref; | ||||
| 			(void)port; | ||||
| 			log("\t%s\n", name.c_str()); | ||||
| 			bits.dump(); | ||||
| 		} | ||||
|  | @ -213,16 +252,6 @@ struct SdcObjects { | |||
| 	} | ||||
| }; | ||||
| 
 | ||||
| template<typename T> | ||||
| static bool parse_flag(char* arg, const char* flag_name, T& flag_var) { | ||||
| 	std::string expected = std::string("-") + flag_name; | ||||
| 	if (expected == arg) { | ||||
| 		flag_var = true; | ||||
| 		return true; | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| // TODO vectors
 | ||||
| // TODO cell arrays?
 | ||||
| struct MatchConfig { | ||||
|  | @ -241,7 +270,7 @@ struct MatchConfig { | |||
| 		hier(hierarchical_flag ? FLAT : TREE) { } | ||||
| }; | ||||
| 
 | ||||
| static std::pair<bool, SdcObjects::BitSelection> matches(std::string name, const std::string& pat, const MatchConfig& config) { | ||||
| static std::pair<bool, BitSelection> matches(std::string name, const std::string& pat, const MatchConfig& config) { | ||||
| 	(void)config; | ||||
| 	bool got_bit_index = false;; | ||||
| 	int bit_idx; | ||||
|  | @ -258,7 +287,7 @@ static std::pair<bool, SdcObjects::BitSelection> matches(std::string name, const | |||
| 		bit_idx = std::stoi(bit_selector); | ||||
| 
 | ||||
| 	} | ||||
| 	SdcObjects::BitSelection bits = {}; | ||||
| 	BitSelection bits = {}; | ||||
| 	if (name == pat_base) { | ||||
| 		if (got_bit_index) { | ||||
| 			bits.set(bit_idx); | ||||
|  | @ -273,33 +302,38 @@ static std::pair<bool, SdcObjects::BitSelection> matches(std::string name, const | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| static int graph_node(TclCall call) { | ||||
| 	// TODO is that it?
 | ||||
| 	return redirect_unknown(call); | ||||
| } | ||||
| 
 | ||||
| static int redirect_unknown(Tcl_Interp *interp, int objc, Tcl_Obj* const objv[]) { | ||||
|     Tcl_Obj *newCmd = Tcl_NewStringObj("unknown", -1); | ||||
| 	auto newObjc = objc + 1; | ||||
|     Tcl_Obj **newObjv = new Tcl_Obj*[newObjc]; | ||||
|     newObjv[0] = newCmd; | ||||
|     for (int i = 1; i < newObjc; i++) { | ||||
|         newObjv[i] = objv[i - 1]; | ||||
| 		log("newObjv %s\n", Tcl_GetString(newObjv[i])); | ||||
|     } | ||||
|     int result = Tcl_EvalObjv(interp, newObjc, newObjv, 0); | ||||
|     Tcl_DecrRefCount(newCmd); | ||||
|     delete[] newObjv; | ||||
| static int redirect_unknown(TclCall call) { | ||||
| 	// TODO redirect to different command
 | ||||
| 	Tcl_Obj *newCmd = Tcl_NewStringObj("unknown", -1); | ||||
| 	auto newObjc = call.objc + 1; | ||||
| 	Tcl_Obj **newObjv = new Tcl_Obj*[newObjc]; | ||||
| 	newObjv[0] = newCmd; | ||||
| 	for (int i = 1; i < newObjc; i++) { | ||||
| 		newObjv[i] = call.objv[i - 1]; | ||||
| 	} | ||||
| 	int result = Tcl_EvalObjv(call.interp, newObjc, newObjv, 0); | ||||
| 	Tcl_DecrRefCount(newCmd); | ||||
| 	delete[] newObjv; | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| struct SdcGraphNode { | ||||
|     using Child = std::variant<SdcGraphNode*, std::string>; | ||||
|     std::vector<Child> children; | ||||
|     SdcGraphNode() = default; | ||||
|     void addChild(SdcGraphNode* child) { | ||||
|         children.push_back(child); | ||||
|     } | ||||
|     void addChild(std::string tcl_string) { | ||||
|         children.push_back(tcl_string); | ||||
|     } | ||||
|     void dump(std::ostream& os) const { | ||||
| 	using Child = std::variant<SdcGraphNode*, std::string>; | ||||
| 	std::vector<Child> children; | ||||
| 	SdcGraphNode() = default; | ||||
| 	void addChild(SdcGraphNode* child) { | ||||
| 		children.push_back(child); | ||||
| 	} | ||||
| 	void addChild(std::string tcl_string) { | ||||
| 		children.push_back(tcl_string); | ||||
| 	} | ||||
| 	void dump(std::ostream& os) const { | ||||
| 		bool first = true; | ||||
| 		for (auto child : children) { | ||||
| 			if (first) { | ||||
|  | @ -317,13 +351,20 @@ struct SdcGraphNode { | |||
| 				log_assert(false); | ||||
| 			} | ||||
| 		} | ||||
|     } | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| static size_t get_node_count(Tcl_Interp* interp) { | ||||
| 	const char* idx_raw = Tcl_GetVar(interp, "sdc_call_index", TCL_GLOBAL_ONLY); | ||||
| 	log_assert(idx_raw); | ||||
| 	std::string idx(idx_raw); | ||||
| 	for (auto c : idx) | ||||
| 		if (!std::isdigit(c)) | ||||
| 			log_error("sdc_call_index non-numeric value %s\n", idx.c_str()); | ||||
| 	return std::stoi(idx); | ||||
| } | ||||
| 
 | ||||
| std::vector<std::vector<std::string>> gather_nested_calls(Tcl_Interp* interp) { | ||||
| 	const char* idx_s = Tcl_GetVar(interp, "sdc_call_index", TCL_GLOBAL_ONLY); | ||||
| 	log_assert(idx_s); | ||||
| 	size_t node_count = std::stoi(idx_s); | ||||
| 
 | ||||
| 	Tcl_Obj* listObj = Tcl_GetVar2Ex(interp, "sdc_calls", nullptr, TCL_GLOBAL_ONLY); | ||||
| 	int listLength; | ||||
|  | @ -354,7 +395,7 @@ std::vector<std::vector<std::string>> gather_nested_calls(Tcl_Interp* interp) { | |||
| 			sdc_calls.push_back(subList); | ||||
| 		} | ||||
| 	} | ||||
| 	log_assert(sdc_calls.size() == node_count); | ||||
| 	log_assert(sdc_calls.size() == get_node_count(interp)); | ||||
| 	return sdc_calls; | ||||
| } | ||||
| 
 | ||||
|  | @ -412,11 +453,13 @@ void inspect_globals(Tcl_Interp* interp) { | |||
| 	std::vector<SdcGraphNode> graph = build_graph(sdc_calls); | ||||
| 	dump_sdc_graph(graph, node_ownership(graph)); | ||||
| } | ||||
| 
 | ||||
| // patterns -> (pattern-object-bit)s
 | ||||
| template <typename T, typename U> | ||||
| std::vector<std::tuple<std::string, T, SdcObjects::BitSelection>> | ||||
| std::vector<std::tuple<std::string, T, BitSelection>> | ||||
| find_matching(U objects, const MatchConfig& config, const std::vector<std::string> &patterns, const char* obj_type) | ||||
| { | ||||
| 	std::vector<std::tuple<std::string, T, SdcObjects::BitSelection>> resolved; | ||||
| 	std::vector<std::tuple<std::string, T, BitSelection>> resolved; | ||||
| 	for (auto pat : patterns) { | ||||
| 		bool found = false; | ||||
| 		for (auto [name, obj] : objects) { | ||||
|  | @ -424,6 +467,7 @@ find_matching(U objects, const MatchConfig& config, const std::vector<std::strin | |||
| 			if (does_match) { | ||||
| 				found = true; | ||||
| 				resolved.push_back(std::make_tuple(name, obj, matching_bits)); | ||||
| 				// TODO add a continue statement, conditional on config
 | ||||
| 			} | ||||
| 		} | ||||
| 		if (!found) | ||||
|  | @ -431,73 +475,120 @@ find_matching(U objects, const MatchConfig& config, const std::vector<std::strin | |||
| 	} | ||||
| 	return resolved; | ||||
| } | ||||
| static int sdc_get_pins_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj* const objv[]) | ||||
| { | ||||
| 	auto* objects = (SdcObjects*)data; | ||||
| 	// When this flag is present, the search for the pattern is made in all positions in the hierarchy.
 | ||||
| struct GetterOpts { | ||||
| 	bool hierarchical_flag = false; | ||||
| 	bool regexp_flag = false; | ||||
| 	bool nocase_flag = false; | ||||
| 	std::string separator = "/"; | ||||
| 	Tcl_Obj* of_objects = nullptr; | ||||
| 	std::vector<std::string> patterns; | ||||
| 	int i = 1; | ||||
| 	for (; i < objc; i++) { | ||||
| 		if (parse_flag(Tcl_GetString(objv[i]), "hierarchical", hierarchical_flag)) continue; | ||||
| 		if (parse_flag(Tcl_GetString(objv[i]), "hier", hierarchical_flag)) continue; | ||||
| 		if (parse_flag(Tcl_GetString(objv[i]), "regexp", regexp_flag)) continue; | ||||
| 		if (parse_flag(Tcl_GetString(objv[i]), "nocase", nocase_flag)) continue; | ||||
| 		if (!strcmp(Tcl_GetString(objv[i]), "-hsc")) { | ||||
| 			separator = Tcl_GetString(objv[++i]); | ||||
| 			continue; | ||||
| 	std::vector<std::string> patterns = {}; | ||||
| 	std::initializer_list<const char*> legals; | ||||
| 	const char* name; | ||||
| 	GetterOpts(const char* name, std::initializer_list<const char*> legals) : legals(legals), name(name) {} | ||||
| 	bool parse_opt(Tcl_Obj* obj, const char* opt_name) { | ||||
| 		char* arg = Tcl_GetString(obj); | ||||
| 		std::string expected = std::string("-") + opt_name; | ||||
| 		if (expected == arg) { | ||||
| 			if (!std::find_if(legals.begin(), legals.end(), | ||||
| 					   [&opt_name](const char* str) { return opt_name == str; })) | ||||
| 				log_cmd_error("Illegal argument %s for %s.\n", expected.c_str(), name); | ||||
| 			return true; | ||||
| 		} | ||||
| 		if (!strcmp(Tcl_GetString(objv[i]), "-of_objects")) { | ||||
| 			of_objects = objv[++i]; | ||||
| 			continue; | ||||
| 		return false; | ||||
| 	} | ||||
| 	template<typename T> | ||||
| 	bool parse_flag(Tcl_Obj* obj, const char* flag_name, T& flag_var) { | ||||
| 		bool ret = parse_opt(obj, flag_name); | ||||
| 		if (ret) | ||||
| 			flag_var = true; | ||||
| 		return ret; | ||||
| 	} | ||||
| 	void parse(int objc, Tcl_Obj* const objv[]) { | ||||
| 		int i = 1; | ||||
| 		for (; i < objc; i++) { | ||||
| 			if (parse_flag(objv[i], "hierarchical", hierarchical_flag)) continue; | ||||
| 			if (parse_flag(objv[i], "hier", hierarchical_flag)) continue; | ||||
| 			if (parse_flag(objv[i], "regexp", regexp_flag)) continue; | ||||
| 			if (parse_flag(objv[i], "nocase", nocase_flag)) continue; | ||||
| 			if (parse_opt(objv[i], "hsc")) { | ||||
| 				log_assert(i + 1 < objc); | ||||
| 				separator = Tcl_GetString(objv[++i]); | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (parse_opt(objv[i], "of_objects")) { | ||||
| 				log_assert(i + 1 < objc); | ||||
| 				of_objects = objv[++i]; | ||||
| 				continue; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		// Onto the next loop
 | ||||
| 		break; | ||||
| 	} | ||||
| 	for (; i < objc; i++) { | ||||
| 		patterns.push_back(Tcl_GetString(objv[i])); | ||||
| 	} | ||||
| 	if (objects->collect_mode == SdcObjects::CollectMode::SimpleGetter) { | ||||
| 		for (; i < objc; i++) { | ||||
| 			patterns.push_back(Tcl_GetString(objv[i])); | ||||
| 		} | ||||
| 	}; | ||||
| 	void check_simple() { | ||||
| 		if (regexp_flag || hierarchical_flag || nocase_flag || separator != "/" || of_objects) { | ||||
| 			log_error("get_pins got unexpected flags in simple mode\n"); | ||||
| 		} | ||||
| 		if (patterns.size() != 1) { | ||||
| 			log_error("get_pins got unexpected number of patterns in simple mode\n"); | ||||
| 			log_error("%s got unexpected flags in simple mode\n", name); | ||||
| 		} | ||||
| 		if (patterns.size() != 1) | ||||
| 			log_error("%s got unexpected number of patterns in simple mode: %zu\n", name, patterns.size()); | ||||
| 	} | ||||
| 	void check_simple_sep() { | ||||
| 		if (separator != "/") | ||||
| 			log_error("Only '/' accepted as separator"); | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| 	MatchConfig config(regexp_flag, nocase_flag, hierarchical_flag); | ||||
| 	std::vector<std::tuple<std::string, SdcObjects::CellPin, SdcObjects::BitSelection>> resolved; | ||||
| // void build_normal_result(Tcl_Interp* interp, size_t list_len, size_t width, const std::string& name, Tcl_Obj*& result, const BitSelection& matching_bits) {
 | ||||
| // 	if (!result)
 | ||||
| // 		result = Tcl_NewListObj(list_len, nullptr);
 | ||||
| // 	for (size_t i = 0; i < width; i++)
 | ||||
| // 		if (matching_bits.is_set(i))
 | ||||
| // 			Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(name.c_str(), name.size()));
 | ||||
| // }
 | ||||
| 
 | ||||
| template <typename T> | ||||
| void merge_or_init(const T& key, dict<T, BitSelection>& dst, const BitSelection& src) { | ||||
| 	if (dst.count(key) == 0) { | ||||
| 		dst[key] = src; | ||||
| 	} else { | ||||
| 		dst[key].merge(src); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static int sdc_get_pins_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj* const objv[]) | ||||
| { | ||||
| 	auto* objects = (SdcObjects*)data; | ||||
| 	GetterOpts opts("get_pins", {"hierarchical", "hier", "regexp", "nocase", "hsc", "of_objects"}); | ||||
| 	opts.parse(objc, objv); | ||||
| 	if (objects->collect_mode == SdcObjects::CollectMode::SimpleGetter) | ||||
| 		opts.check_simple(); | ||||
| 	opts.check_simple_sep(); | ||||
| 
 | ||||
| 	MatchConfig config(opts.regexp_flag, opts.nocase_flag, opts.hierarchical_flag); | ||||
| 	std::vector<std::tuple<std::string, SdcObjects::CellPin, BitSelection>> resolved; | ||||
| 	const auto& pins = objects->design_pins; | ||||
| 	resolved = find_matching<SdcObjects::CellPin, decltype(pins)>(pins, config, patterns, "pin"); | ||||
| 
 | ||||
| 	if (separator != "/") { | ||||
| 		Tcl_SetResult(interp, (char *)"Only '/' accepted as separator", TCL_STATIC); | ||||
| 		return TCL_ERROR; | ||||
| 	} | ||||
| 	resolved = find_matching<SdcObjects::CellPin, decltype(pins)>(pins, config, opts.patterns, "pin"); | ||||
| 
 | ||||
| 	Tcl_Obj *result = nullptr; | ||||
| 	for (auto [name, pin, matching_bits] : resolved) { | ||||
| 		if (objects->value_mode == SdcObjects::ValueMode::Normal) { | ||||
| 			if (!result) | ||||
| 				result = Tcl_NewListObj(resolved.size(), nullptr); | ||||
| 			size_t width = (size_t)pin.first->getPort(pin.second).size(); | ||||
| 			for (size_t i = 0; i < width; i++) | ||||
| 				if (matching_bits.is_set(i)) | ||||
| 					Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(name.c_str(), name.size())); | ||||
| 		} | ||||
| 	if (objects->value_mode == SdcObjects::ValueMode::Normal) { | ||||
| 		log_error("TODO normal\n"); | ||||
| 		auto width = [](SdcObjects::CellPin& pin) -> size_t { | ||||
| 			return (size_t)pin.first->getPort(pin.second).size(); | ||||
| 		}; | ||||
| 		objects->build_normal_result<SdcObjects::CellPin, decltype(objects->resolved_pin_pattern_sets)>(interp, std::move(resolved), objects->resolved_pin_pattern_sets, width, result); | ||||
| 	} else if (objects->value_mode == SdcObjects::ValueMode::Graph) | ||||
| 		return graph_node(TclCall{interp, objc, objv}); | ||||
| 
 | ||||
| 		if (objects->collect_mode != SdcObjects::CollectMode::FullConstraint) | ||||
| 			objects->constrained_pins[std::make_pair(name, pin)].merge(matching_bits); | ||||
| 	} | ||||
| 	if (objects->collect_mode != SdcObjects::CollectMode::FullConstraint) | ||||
| 		objects->merge_as_constrained(std::move(resolved)); | ||||
| 		// merge_or_init(std::make_pair(name, pin), objects->constrained_pins, matching_bits);
 | ||||
| 		// TODO
 | ||||
| 	// }
 | ||||
| 
 | ||||
| 	 | ||||
| 		// return objects->graph_node(interp, objc, objv, std::move(resolved), objects->resolved_pin_pattern_sets);
 | ||||
| 
 | ||||
| 	if (objects->value_mode == SdcObjects::ValueMode::Graph) { | ||||
| 		return redirect_unknown(interp, objc, objv); | ||||
| 	} | ||||
| 	if (result) | ||||
| 		Tcl_SetObjResult(interp, result); | ||||
| 	return TCL_OK; | ||||
|  | @ -506,57 +597,32 @@ static int sdc_get_pins_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_O | |||
| static int sdc_get_ports_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj* const objv[]) | ||||
| { | ||||
| 	auto* objects = (SdcObjects*)data; | ||||
| 	bool regexp_flag = false; | ||||
| 	bool nocase_flag = false; | ||||
| 	std::vector<std::string> patterns; | ||||
| 	int i = 1; | ||||
| 	for (; i < objc; i++) { | ||||
| 		if (parse_flag(Tcl_GetString(objv[i]), "regexp", regexp_flag)) continue; | ||||
| 		if (parse_flag(Tcl_GetString(objv[i]), "nocase", nocase_flag)) continue; | ||||
| 		// Onto the next loop
 | ||||
| 		break; | ||||
| 	} | ||||
| 	for (; i < objc; i++) { | ||||
| 		patterns.push_back(Tcl_GetString(objv[i])); | ||||
| 	} | ||||
| 	if (objects->collect_mode == SdcObjects::CollectMode::SimpleGetter) { | ||||
| 		if (regexp_flag || nocase_flag) { | ||||
| 			log_error("get_ports got unexpected flags in simple mode\n"); | ||||
| 		} | ||||
| 		if (patterns.size() != 1) { | ||||
| 			log_error("get_ports got unexpected number of patterns in simple mode\n"); | ||||
| 		} | ||||
| 	} | ||||
| 	GetterOpts opts("get_ports", {"regexp", "nocase"}); | ||||
| 	opts.parse(objc, objv); | ||||
| 	if (objects->collect_mode == SdcObjects::CollectMode::SimpleGetter) | ||||
| 		opts.check_simple(); | ||||
| 
 | ||||
| 	MatchConfig config(regexp_flag, nocase_flag, false); | ||||
| 	std::vector<std::tuple<std::string, Wire*, SdcObjects::BitSelection>> resolved; | ||||
| 	MatchConfig config(opts.regexp_flag, opts.nocase_flag, false); | ||||
| 	std::vector<std::tuple<std::string, Wire*, BitSelection>> resolved; | ||||
| 	const auto& ports = objects->design_ports; | ||||
| 	resolved = find_matching<Wire*, decltype(ports)>(ports, config, patterns, "port"); | ||||
| 	resolved = find_matching<Wire*, decltype(ports)>(ports, config, opts.patterns, "port"); | ||||
| 
 | ||||
| 	Tcl_Obj *result = nullptr; | ||||
| 	for (auto [name, wire, matching_bits] : resolved) { | ||||
| 		if (objects->value_mode == SdcObjects::ValueMode::Normal) { | ||||
| 			if (!result) | ||||
| 				result = Tcl_NewListObj(resolved.size(), nullptr); | ||||
| 			size_t width = wire->width; | ||||
| 			for (size_t i = 0; i < width; i++) | ||||
| 				if (matching_bits.is_set(i)) | ||||
| 					Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(name.c_str(), name.size())); | ||||
| 		} | ||||
| 		if (objects->collect_mode != SdcObjects::CollectMode::FullConstraint) { | ||||
| 			if (objects->constrained_ports.count(name) == 0) { | ||||
| 				objects->constrained_ports[name] = matching_bits; | ||||
| 			} else { | ||||
| 				objects->constrained_ports[name].merge(matching_bits); | ||||
| 			} | ||||
| 		} | ||||
| 		if (objects->value_mode == SdcObjects::ValueMode::Normal) | ||||
| 			log_error("TODO normal\n"); | ||||
| 			// objects->build_normal_result(interp, resolved.size(), wire->width, name, result, matching_bits);
 | ||||
| 
 | ||||
| 		if (objects->collect_mode != SdcObjects::CollectMode::FullConstraint) | ||||
| 			merge_or_init(std::make_pair(name, wire), objects->constrained_ports, matching_bits); | ||||
| 	} | ||||
| 
 | ||||
| 	if (objects->value_mode == SdcObjects::ValueMode::Graph) { | ||||
| 		return redirect_unknown(interp, objc, objv); | ||||
| 		return graph_node(TclCall{interp, objc, objv}); | ||||
| 		// return objects->graph_node(interp, objc, objv, std::move(resolved), objects->resolved_port_pattern_sets);
 | ||||
| 	} | ||||
| 
 | ||||
| 	Tcl_SetObjResult(interp, result); | ||||
| 	if (result) | ||||
| 		Tcl_SetObjResult(interp, result); | ||||
| 	return TCL_OK; | ||||
| } | ||||
| 
 | ||||
|  | @ -592,10 +658,10 @@ static int ys_track_typed_key_cmd(ClientData data, Tcl_Interp *interp, int objc, | |||
| 	if (objects->collect_mode != SdcObjects::CollectMode::FullConstraint) | ||||
| 		return TCL_OK; | ||||
| 
 | ||||
| 	std::string key_name         = Tcl_GetString(objv[1]); | ||||
| 	Tcl_Obj* key_value           = objv[2]; | ||||
| 	std::string key_name		 = Tcl_GetString(objv[1]); | ||||
| 	Tcl_Obj* key_value		   = objv[2]; | ||||
| 	std::string key_expect_type  = Tcl_GetString(objv[3]); | ||||
| 	std::string proc_name        = Tcl_GetString(objv[4]); | ||||
| 	std::string proc_name		= Tcl_GetString(objv[4]); | ||||
| 
 | ||||
| 	auto track_typed = [key_expect_type, objects, proc_name, key_name](const char* str) -> void { | ||||
| 		auto split = split_at(str); | ||||
|  | @ -608,7 +674,7 @@ static int ys_track_typed_key_cmd(ClientData data, Tcl_Interp *interp, int objc, | |||
| 			bool found = false; | ||||
| 			for (auto [name, pin] : objects->design_pins) { | ||||
| 				log_error("TODO temporarily disabled due to working on a different flow\n"); | ||||
| 				// if (name + "/" + pin->name.str() == str) {
 | ||||
| 				// if (name + "/" + pin.name.str() == str) {
 | ||||
| 				// 	found = true;
 | ||||
| 				// 	objects->constrained_pins.insert(std::make_pair(name, pin));
 | ||||
| 				// 	break; // resolved, expected unique
 | ||||
|  | @ -674,7 +740,7 @@ public: | |||
| struct SdcPass : public Pass { | ||||
| 	// TODO help
 | ||||
| 	SdcPass() : Pass("sdc", "sniff at some SDC") { } | ||||
| 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 SDC pass.\n"); | ||||
| 		size_t argidx; | ||||
| 		std::vector<std::string> opensta_stubs_paths; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue