diff --git a/passes/cmds/sdc.cc b/passes/cmds/sdc.cc index dd46b1ee4..b01cbe025 100644 --- a/passes/cmds/sdc.cc +++ b/passes/cmds/sdc.cc @@ -5,6 +5,7 @@ #include #include #include +#include USING_YOSYS_NAMESPACE @@ -12,10 +13,11 @@ PRIVATE_NAMESPACE_BEGIN struct SdcObjects { - enum GetterMode { - Simple, - Full - } mode; + enum CollectMode { + SimpleGetter, + FullGetter, + FullConstraint, + } collect_mode; std::vector design_ports; std::vector> design_cells; std::vector> design_pins; @@ -90,26 +92,26 @@ struct SdcObjects { constrained_cells.sort(); constrained_pins.sort(); constrained_nets.sort(); - 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("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()); @@ -169,7 +171,6 @@ static bool matches(std::string name, const std::string& pat, const MatchConfig& 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; @@ -198,7 +199,7 @@ static int sdc_get_pins_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_O for (; i < objc; i++) { patterns.push_back(Tcl_GetString(objv[i])); } - if (objects->mode == SdcObjects::GetterMode::Simple) { + if (objects->collect_mode == SdcObjects::CollectMode::SimpleGetter) { if (regexp_flag || hierarchical_flag || nocase_flag || separator != "/" || of_objects) { log_error("get_pins got unexpected flags in simple mode\n"); } @@ -210,7 +211,6 @@ static int sdc_get_pins_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_O MatchConfig config(regexp_flag, nocase_flag, hierarchical_flag); std::vector> resolved; for (auto pat : patterns) { - log("get_pins sniffs %s\n", pat.c_str()); bool found = false; for (auto [name, pin] : objects->design_pins) { if (matches(name, pat, config)) { @@ -224,7 +224,8 @@ static int sdc_get_pins_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_O Tcl_Obj *result = Tcl_NewListObj(resolved.size(), nullptr); for (auto obj : resolved) { Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(obj.first.c_str(), obj.first.size())); - objects->constrained_pins.insert(obj); + if (objects->collect_mode != SdcObjects::CollectMode::FullConstraint) + objects->constrained_pins.insert(obj); } if (separator != "/") { @@ -238,7 +239,6 @@ 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[]) { - (void)interp; auto* objects = (SdcObjects*)data; bool regexp_flag = false; bool nocase_flag = false; @@ -253,7 +253,7 @@ static int sdc_get_ports_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_ for (; i < objc; i++) { patterns.push_back(Tcl_GetString(objv[i])); } - if (objects->mode == SdcObjects::GetterMode::Simple) { + if (objects->collect_mode == SdcObjects::CollectMode::SimpleGetter) { if (regexp_flag || nocase_flag) { log_error("get_ports got unexpected flags in simple mode\n"); } @@ -277,13 +277,89 @@ static int sdc_get_ports_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_ Tcl_Obj *result = Tcl_NewListObj(resolved.size(), nullptr); for (auto obj : resolved) { Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(obj.c_str(), obj.size())); - objects->constrained_ports.insert(obj); + if (objects->collect_mode != SdcObjects::CollectMode::FullConstraint) + objects->constrained_ports.insert(obj); } Tcl_SetObjResult(interp, result); return TCL_OK; } +std::optional> split_at(std::string s) +{ + size_t pos = s.find('@'); + if (pos == std::string::npos) + return std::nullopt; + return std::make_tuple(s.substr(0, pos), s.substr(pos + 1)); +} + +// Whether string or list of strings, apply op to each string +void apply_args(Tcl_Interp *interp, std::function op, Tcl_Obj* obj) +{ + int length; + Tcl_Obj **value_list; + if (Tcl_ListObjGetElements(interp, obj, &length, &value_list) == TCL_OK) { + for (int i = 0; i < length; i++) { + op(Tcl_GetString(value_list[i])); + } + } else { + op(Tcl_GetString(obj)); + } +} + +static int ys_track_typed_key_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj* const objv[]) +{ + log("ys_track_typed_key_cmd\n"); + auto* objects = (SdcObjects*)data; + if (objc != 5) + log_error("ys_track_typed_key: Unexpected number of arguments: %d (expected 5)\n", 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_expect_type = Tcl_GetString(objv[3]); + 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); + if (!split) + log_error("%s: key %s should be a typed SDC object, but is something weird: %s\n", + proc_name.c_str(), key_name.c_str(), str); + + if (key_expect_type == "pin") { + log("PIN! %s\n", str); + bool found = false; + for (auto [name, pin] : objects->design_pins) { + if (name + "/" + pin->name.str() == str) { + found = true; + objects->constrained_pins.insert(std::make_pair(name, pin)); + break; // resolved, expected unique + } + } + if (!found) + log_error("%s: pin %s not found\n", proc_name.c_str(), str); + } else if (key_expect_type == "port") { + bool found = false; + for (auto name : objects->design_ports) { + if (name == str) { + found = true; + objects->constrained_ports.insert(name); + break; // resolved, expected unique + } + } + if (!found) + log_error("%s: port %s not found\n", proc_name.c_str(), str); + } else { + // TODO + log_warning("%s: unsupported type %s\n", proc_name.c_str(), key_expect_type.c_str()); + } + }; + apply_args(interp, track_typed, key_value); + return TCL_OK; +} + class SDCInterpreter { @@ -308,8 +384,10 @@ public: log_error("Tcl_Init() call failed - %s\n",Tcl_ErrnoMsg(Tcl_GetErrno())); objects = std::make_unique(design); + objects->collect_mode = SdcObjects::CollectMode::FullConstraint; 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); + Tcl_CreateObjCommand(interp, "ys_track_typed_key", ys_track_typed_key_cmd, (ClientData) objects.get(), NULL); return interp; } }; diff --git a/passes/cmds/stubs.sdc b/passes/cmds/stubs.sdc index 93358cb43..3466981c9 100644 --- a/passes/cmds/stubs.sdc +++ b/passes/cmds/stubs.sdc @@ -15,7 +15,7 @@ proc get_clocks {args} { } stub current_design -stub ys_track_typed_key +#stub ys_track_typed_key stub ys_track_untyped_key stub ys_err_key stub ys_err_flag