blob: 66401a6574a00207dbd298fd62d90b4b2e7a66ea [file] [log] [blame]
#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));
}