diff --git a/passes/cmds/sdc.cc b/passes/cmds/sdc.cc index 0343c6b09..4d7347f54 100644 --- a/passes/cmds/sdc.cc +++ b/passes/cmds/sdc.cc @@ -9,6 +9,117 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN + +struct SdcObjects { + std::vector design_ports; + std::vector> design_cells; + std::vector> design_pins; + std::vector> design_nets; + + pool constrained_ports; + pool> constrained_cells; + pool> constrained_pins; + pool> constrained_nets; + + void sniff_module(std::list& hierarchy, Module* mod) { + std::string prefix; + for (auto mod_name : hierarchy) { + if (prefix.length()) + prefix += "/"; // TODO seperator? + prefix += mod_name; + } + + for (auto* wire : mod->wires()) { + std::string name = wire->name.str(); + log_assert(name.length()); + // TODO: really skip internal wires? + if (name[0] == '$') + continue; + name = name.substr(1); + std::string path = prefix; + if (path.length()) + path += "/"; + path += name; + design_nets.push_back(std::make_pair(path, wire)); + } + + for (auto* cell : mod->cells()) { + std::string name = cell->name.str(); + // TODO: really skip internal cells? + if (name[0] == '$') + continue; + name = name.substr(1); + std::string path = prefix; + if (path.length()) + path += "/"; + path += name; + design_cells.push_back(std::make_pair(path, cell)); + for (auto pin : cell->connections()) { + std::string pin_name = path + "/" + pin.first.str().substr(1); + design_pins.push_back(std::make_pair(pin_name, cell)); + } + if (auto sub_mod = mod->design->module(cell->type)) { + hierarchy.push_back(name); + sniff_module(hierarchy, sub_mod); + hierarchy.pop_back(); + } + } + } + SdcObjects(Design* design) { + Module* top = design->top_module(); + if (!top) + log_error("Top module couldn't be determined. Check 'top' attribute usage"); + for (auto port : top->ports) { + design_ports.push_back(port.str().substr(1)); + } + std::list hierarchy{}; + sniff_module(hierarchy, top); + } + ~SdcObjects() = default; + void dump() { + log("Design ports:\n"); + for (auto name : design_ports) { + log("\t%s\n", name.c_str()); + } + log("Design cells:\n"); + for (auto [name, cell] : design_cells) { + (void)cell; + log("\t%s\n", name.c_str()); + } + log("Design pins:\n"); + for (auto [name, pin] : design_pins) { + (void)pin; + log("\t%s\n", name.c_str()); + } + log("Design nets:\n"); + for (auto [name, net] : design_nets) { + (void)net; + log("\t%s\n", name.c_str()); + } + log("\n"); + log("Constrained ports:\n"); + for (auto name : constrained_ports) { + log("\t%s\n", name.c_str()); + } + log("Constrained cells:\n"); + for (auto [name, cell] : constrained_cells) { + (void)cell; + log("\t%s\n", name.c_str()); + } + log("Constrained pins:\n"); + for (auto [name, pin] : constrained_pins) { + (void)pin; + log("\t%s\n", name.c_str()); + } + log("Constrained nets:\n"); + for (auto [name, net] : constrained_nets) { + (void)net; + log("\t%s\n", name.c_str()); + } + log("\n"); + } +}; + template static bool parse_flag(char* arg, const char* flag_name, T& flag_var) { std::string expected = std::string("-") + flag_name; @@ -23,9 +134,10 @@ static bool parse_flag(char* arg, const char* flag_name, T& flag_var) { // TODO vectors // TODO cell arrays? -static int sdc_get_pins_cmd(ClientData, Tcl_Interp *interp, int objc, Tcl_Obj* const objv[]) +static int sdc_get_pins_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj* const objv[]) { (void)interp; + auto* objects = (SdcObjects*)data; // When this flag is present, the search for the pattern is made in all positions in the hierarchy. bool hierarchical_flag = false; bool regexp_flag = false; @@ -53,9 +165,16 @@ static int sdc_get_pins_cmd(ClientData, Tcl_Interp *interp, int objc, Tcl_Obj* c for (; i < objc; i++) { patterns.push_back(Tcl_GetString(objv[i])); } - log("get_pins patterns:\n"); for (auto pat : patterns) { - log("\t%s\n", pat.c_str()); + bool found = false; + for (auto [name, pin] : objects->design_pins) { + if (name == pat) { + found = true; + objects->constrained_pins.insert(std::make_pair(name, pin)); + } + } + if (!found) + log_warning("No matches in design for pattern %s\n", pat.c_str()); } (void)hierarchical_flag; (void)regexp_flag; @@ -68,9 +187,10 @@ static int sdc_get_pins_cmd(ClientData, Tcl_Interp *interp, int objc, Tcl_Obj* c return TCL_OK; } -static int sdc_get_ports_cmd(ClientData, Tcl_Interp *interp, int objc, Tcl_Obj* const objv[]) +static int sdc_get_ports_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj* const objv[]) { (void)interp; + auto* objects = (SdcObjects*)data; bool regexp_flag = false; bool nocase_flag = false; std::vector patterns; @@ -84,20 +204,29 @@ static int sdc_get_ports_cmd(ClientData, Tcl_Interp *interp, int objc, Tcl_Obj* for (; i < objc; i++) { patterns.push_back(Tcl_GetString(objv[i])); } - log("get_ports patterns:\n"); for (auto pat : patterns) { - log("\t%s\n", pat.c_str()); + bool found = false; + for (auto name : objects->design_ports) { + if (name == pat) { + found = true; + objects->constrained_ports.insert(name); + } + } + if (!found) + log_warning("No matches in design for pattern %s\n", pat.c_str()); } (void)regexp_flag; (void)nocase_flag; return TCL_OK; } + class SDCInterpreter { private: Tcl_Interp* interp = nullptr; public: + std::unique_ptr objects; ~SDCInterpreter() { if (interp) Tcl_DeleteInterp(interp); @@ -106,105 +235,21 @@ public: static SDCInterpreter instance; return instance; } - Tcl_Interp* fresh_interp() { + Tcl_Interp* fresh_interp(Design* design) { if (interp) Tcl_DeleteInterp(interp); + interp = Tcl_CreateInterp(); if (Tcl_Init(interp)!=TCL_OK) - log_warning("Tcl_Init() call failed - %s\n",Tcl_ErrnoMsg(Tcl_GetErrno())); - Tcl_CreateObjCommand(interp, "get_pins", sdc_get_pins_cmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "get_ports", sdc_get_ports_cmd, NULL, NULL); + log_error("Tcl_Init() call failed - %s\n",Tcl_ErrnoMsg(Tcl_GetErrno())); + + objects = std::make_unique(design); + Tcl_CreateObjCommand(interp, "get_pins", sdc_get_pins_cmd, (ClientData) objects.get(), NULL); + Tcl_CreateObjCommand(interp, "get_ports", sdc_get_ports_cmd, (ClientData) objects.get(), NULL); return interp; } }; -struct SdcObjects { - std::vector ports; - std::vector> cells; - std::vector> pins; - std::vector> nets; - - void sniff_module(std::list& hierarchy, Module* mod) { - log_debug("sniffing module %s\n", mod->name.c_str()); - - std::string prefix; - for (auto mod_name : hierarchy) { - if (prefix.length()) - prefix += "/"; // TODO seperator? - prefix += mod_name; - } - - for (auto* wire : mod->wires()) { - std::string name = wire->name.str(); - log_assert(name.length()); - // TODO: really skip internal wires? - if (name[0] == '$') - continue; - name = name.substr(1); - std::string path = prefix; - if (path.length()) - path += "/"; - path += name; - nets.push_back(std::make_pair(path, wire)); - } - - for (auto* cell : mod->cells()) { - std::string name = cell->name.str(); - // TODO: really skip internal cells? - if (name[0] == '$') - continue; - name = name.substr(1); - std::string path = prefix; - if (path.length()) - path += "/"; - path += name; - cells.push_back(std::make_pair(path, cell)); - for (auto pin : cell->connections()) { - std::string pin_name = path + "/" + pin.first.str().substr(1); - pins.push_back(std::make_pair(pin_name, cell)); - } - if (auto sub_mod = mod->design->module(cell->type)) { - hierarchy.push_back(name); - sniff_module(hierarchy, sub_mod); - hierarchy.pop_back(); - } - } - } - SdcObjects(Design* design) { - Module* top = design->top_module(); - if (!top) - log_error("Top module couldn't be determined. Check 'top' attribute usage"); - for (auto port : top->ports) { - ports.push_back(port.str().substr(1)); - } - std::list hierarchy{}; - sniff_module(hierarchy, top); - } - void dump() { - log("Dumping detected design objects visible to SDC constraints\n"); - log("Ports:\n"); - for (auto name : ports) { - log("\t%s\n", name.c_str()); - } - log("Cells:\n"); - for (auto [name, cell] : cells) { - (void)cell; - log("\t%s\n", name.c_str()); - } - log("Pins:\n"); - for (auto [name, pin] : pins) { - (void)pin; - log("\t%s\n", name.c_str()); - } - log("Nets:\n"); - for (auto [name, net] : nets) { - (void)net; - log("\t%s\n", name.c_str()); - } - log("\n"); - } -}; - // Also see TclPass struct SdcPass : public Pass { // TODO help @@ -213,16 +258,16 @@ struct SdcPass : public Pass { if (args.size() < 2) log_cmd_error("Missing SDC file.\n"); // TODO optional extra stub file - Tcl_Interp *interp = SDCInterpreter::get().fresh_interp(); + SDCInterpreter& sdc = SDCInterpreter::get(); + Tcl_Interp *interp = sdc.fresh_interp(design); Tcl_Preserve(interp); std::string stub_path = "+/sdc/stubs.sdc"; rewrite_filename(stub_path); - SdcObjects objects(design); - objects.dump(); if (Tcl_EvalFile(interp, stub_path.c_str()) != TCL_OK) log_cmd_error("SDC interpreter returned an error in stub file: %s\n", Tcl_GetStringResult(interp)); if (Tcl_EvalFile(interp, args[1].c_str()) != TCL_OK) log_cmd_error("SDC interpreter returned an error: %s\n", Tcl_GetStringResult(interp)); + sdc.objects->dump(); Tcl_Release(interp); } } SdcPass; diff --git a/tests/various/sdc.sdc b/tests/various/sdc.sdc index 69efcb40a..2143b34d7 100644 --- a/tests/various/sdc.sdc +++ b/tests/various/sdc.sdc @@ -1,5 +1,5 @@ puts "SDC constraints file says hello from arbitrary Tcl execution" set_false_path -from [get_pins s1/sa] -to [get_pins s1/sb] puts "This should print something:" -puts [get_ports {slink_clk_o slink_*_o}] +puts [get_ports a b] puts "Did it?" \ No newline at end of file