|  | #include "get_cmd.h" | 
|  |  | 
|  | USING_YOSYS_NAMESPACE | 
|  |  | 
|  | void GetCmd::help() | 
|  | { | 
|  | //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| | 
|  | log("\n"); | 
|  | log("   get_%ss [-quiet] [-filter filter_expression] " | 
|  | "<%s_selection> \n", | 
|  | TypeName().c_str(), TypeName().c_str()); | 
|  | log("\n"); | 
|  | log("Get matching %ss\n", TypeName().c_str()); | 
|  | log("\n"); | 
|  | log("Print the output to stdout too. This is useful when all Yosys " | 
|  | "is " | 
|  | "executed.\n"); | 
|  | log("\n"); | 
|  | log("    -filter\n"); | 
|  | log("        Name and value of attribute to be taken into " | 
|  | "account.\n"); | 
|  | log("        e.g. -filter { attr == \"true\" }\n"); | 
|  | log("\n"); | 
|  | log("    -quiet\n"); | 
|  | log("        Don't print the result of the execution to stdout.\n"); | 
|  | log("\n"); | 
|  | log("    <selection_pattern>\n"); | 
|  | log("        Selection of %s names. Default are all %ss in the " | 
|  | "design.\n", | 
|  | TypeName().c_str(), TypeName().c_str()); | 
|  | log("\n"); | 
|  | } | 
|  |  | 
|  | void GetCmd::ExecuteSelection(RTLIL::Design *design, const CommandArgs &args) | 
|  | { | 
|  | std::vector<std::string> selection_args; | 
|  | // Add name of top module to selection string | 
|  | std::transform(args.selection_objects.begin(), args.selection_objects.end(), std::back_inserter(selection_args), | 
|  | [&](const std::string &obj) { return RTLIL::unescape_id(design->top_module()->name) + "/" + SelectionType() + ":" + obj; }); | 
|  | extra_args(selection_args, 0, design); | 
|  | if (design->selected_modules().empty()) { | 
|  | if (!args.is_quiet) { | 
|  | log_warning("Specified %s not found in design\n", TypeName().c_str()); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void GetCmd::PackToTcl(const SelectionObjects &objects) | 
|  | { | 
|  | Tcl_Obj *tcl_result; | 
|  | if (objects.size() == 1) { | 
|  | tcl_result = Tcl_NewStringObj(objects.at(0).c_str(), -1); | 
|  | } else { | 
|  | tcl_result = Tcl_NewListObj(0, NULL); | 
|  | for (const auto &object : objects) { | 
|  | Tcl_Obj *value_obj = Tcl_NewStringObj(object.c_str(), -1); | 
|  | Tcl_ListObjAppendElement(yosys_get_tcl_interp(), tcl_result, value_obj); | 
|  | } | 
|  | } | 
|  | Tcl_SetObjResult(yosys_get_tcl_interp(), tcl_result); | 
|  | } | 
|  |  | 
|  | GetCmd::CommandArgs GetCmd::ParseCommand(const std::vector<std::string> &args) | 
|  | { | 
|  | CommandArgs parsed_args{.filters = Filters(), .is_quiet = false, .selection_objects = SelectionObjects()}; | 
|  | size_t argidx(0); | 
|  | for (argidx = 1; argidx < args.size(); argidx++) { | 
|  | std::string arg = args[argidx]; | 
|  | if (arg == "-quiet") { | 
|  | parsed_args.is_quiet = true; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (arg == "-filter" and argidx + 1 < args.size()) { | 
|  | std::string filter_arg = args[++argidx]; | 
|  |  | 
|  | // Remove spaces | 
|  | filter_arg.erase(std::remove_if(filter_arg.begin(), filter_arg.end(), isspace), filter_arg.end()); | 
|  |  | 
|  | // Parse filters | 
|  | // TODO Add support for multiple condition expression | 
|  | // Currently only a single == is supported | 
|  | std::regex filter_attr_regex("(\\w+\\s?==\\s?\\w+)([(||)(&&)]*)"); | 
|  | std::regex_token_iterator<std::string::iterator> regex_end; | 
|  | std::regex_token_iterator<std::string::iterator> matches(filter_arg.begin(), filter_arg.end(), filter_attr_regex, 1); | 
|  | if (matches == regex_end) { | 
|  | log_warning("Currently -filter switch supports only a single " | 
|  | "'equal(==)' condition expression, the rest will be " | 
|  | "ignored\n"); | 
|  | } | 
|  |  | 
|  | while (matches != regex_end) { | 
|  | std::string filter(*matches++); | 
|  | auto separator = filter.find("=="); | 
|  | if (separator == std::string::npos) { | 
|  | log_cmd_error("Incorrect filter expression: %s\n", args[argidx].c_str()); | 
|  | } | 
|  | parsed_args.filters.emplace_back(filter.substr(0, separator), filter.substr(separator + 2)); | 
|  | } | 
|  | if (parsed_args.filters.size() > 1) { | 
|  | log_warning("Currently -filter switch supports only a single " | 
|  | "'equal(==)' condition expression, the rest will be " | 
|  | "ignored\n"); | 
|  | } | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (arg.size() > 0 and arg[0] == '-') { | 
|  | log_cmd_error("Unknown option %s.\n", arg.c_str()); | 
|  | } | 
|  |  | 
|  | break; | 
|  | } | 
|  | std::copy(args.begin() + argidx, args.end(), std::back_inserter(parsed_args.selection_objects)); | 
|  | return parsed_args; | 
|  | } | 
|  |  | 
|  | void GetCmd::execute(std::vector<std::string> args, RTLIL::Design *design) | 
|  | { | 
|  | if (design->top_module() == nullptr) { | 
|  | log_cmd_error("No top module detected\n"); | 
|  | } | 
|  |  | 
|  | CommandArgs parsed_args(ParseCommand(args)); | 
|  | ExecuteSelection(design, parsed_args); | 
|  | PackToTcl(ExtractSelection(design, parsed_args)); | 
|  | } |