mirror of
https://github.com/YosysHQ/yosys
synced 2025-10-09 17:31:59 +00:00
sdc: start graph
This commit is contained in:
parent
cd244d0d02
commit
2eb842e8b4
2 changed files with 110 additions and 8 deletions
|
@ -14,10 +14,19 @@ PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
struct SdcObjects {
|
struct SdcObjects {
|
||||||
enum CollectMode {
|
enum CollectMode {
|
||||||
|
// getter-side object tracking with minimal features
|
||||||
SimpleGetter,
|
SimpleGetter,
|
||||||
|
// getter-side object tracking with everything
|
||||||
FullGetter,
|
FullGetter,
|
||||||
|
// constraint-side tracking
|
||||||
FullConstraint,
|
FullConstraint,
|
||||||
} collect_mode;
|
} collect_mode;
|
||||||
|
enum ValueMode {
|
||||||
|
// return something sensible and error on unknown
|
||||||
|
Normal,
|
||||||
|
// return a new graph node assuming unknown is overridden
|
||||||
|
Graph,
|
||||||
|
} value_mode;
|
||||||
struct BitSelection {
|
struct BitSelection {
|
||||||
bool all = false;
|
bool all = false;
|
||||||
std::vector<bool> bits = {};
|
std::vector<bool> bits = {};
|
||||||
|
@ -263,6 +272,85 @@ static std::pair<bool, SdcObjects::BitSelection> matches(std::string name, const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int redirect_unknown(Tcl_Interp *interp, int objc, Tcl_Obj* const objv[]) {
|
||||||
|
Tcl_Obj *newCmd = Tcl_NewStringObj("unknown", -1);
|
||||||
|
Tcl_Obj **newObjv = new Tcl_Obj*[objc+1];
|
||||||
|
newObjv[0] = newCmd;
|
||||||
|
for (int i = 1; i < objc + 1; i++) {
|
||||||
|
newObjv[i] = objv[i - 1];
|
||||||
|
}
|
||||||
|
int result = Tcl_EvalObjv(interp, objc, newObjv, 0);
|
||||||
|
Tcl_DecrRefCount(newCmd);
|
||||||
|
delete[] newObjv;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void inspect_globals(Tcl_Interp* interp) {
|
||||||
|
auto get_var = [&](const char* name) -> const char* {
|
||||||
|
return Tcl_GetVar(interp, name, TCL_GLOBAL_ONLY);
|
||||||
|
};
|
||||||
|
const char* idx_s = get_var("sdc_call_index");
|
||||||
|
log_assert(idx_s);
|
||||||
|
size_t node_count = std::stoi(idx_s);
|
||||||
|
|
||||||
|
// else
|
||||||
|
// printf("sdc_call_index: unset\n");
|
||||||
|
// if (auto calls = get_var("sdc_calls"))
|
||||||
|
// printf("sdc_calls: %s\n", calls);
|
||||||
|
// else
|
||||||
|
// printf("sdc_calls: unset\n");
|
||||||
|
Tcl_Obj* listObj = Tcl_GetVar2Ex(interp, "sdc_calls", nullptr, TCL_GLOBAL_ONLY);
|
||||||
|
int listLength;
|
||||||
|
|
||||||
|
// Get list length first
|
||||||
|
std::vector<std::vector<std::string>> nestedData;
|
||||||
|
if (Tcl_ListObjLength(interp, listObj, &listLength) == TCL_OK) {
|
||||||
|
for (int i = 0; i < listLength; i++) {
|
||||||
|
Tcl_Obj* subListObj;
|
||||||
|
std::vector<std::string> subList;
|
||||||
|
if (Tcl_ListObjIndex(interp, listObj, i, &subListObj) != TCL_OK) {
|
||||||
|
log_error("broken list of lists\n");
|
||||||
|
}
|
||||||
|
int subListLength;
|
||||||
|
if (Tcl_ListObjLength(interp, subListObj, &subListLength) == TCL_OK) {
|
||||||
|
// It's a valid list - extract elements
|
||||||
|
for (int j = 0; j < subListLength; j++) {
|
||||||
|
Tcl_Obj* elementObj;
|
||||||
|
if (Tcl_ListObjIndex(interp, subListObj, j, &elementObj) == TCL_OK) {
|
||||||
|
const char* elementStr = Tcl_GetString(elementObj);
|
||||||
|
subList.push_back(std::string(elementStr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// It's a single element, not a list
|
||||||
|
const char* elementStr = Tcl_GetString(subListObj);
|
||||||
|
subList.push_back(std::string(elementStr));
|
||||||
|
}
|
||||||
|
nestedData.push_back(subList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::vector<bool> has_parent;
|
||||||
|
log_assert(nestedData.size() == node_count);
|
||||||
|
has_parent.resize(node_count);
|
||||||
|
for (size_t i = 0; i < node_count; i++) {
|
||||||
|
for (size_t j = 0; j < nestedData[i].size(); j++) {
|
||||||
|
auto arg = nestedData[i][j];
|
||||||
|
auto pos = arg.find("YOSYS_SDC_MAGIC_NODE_");
|
||||||
|
if (pos == std::string::npos)
|
||||||
|
continue;
|
||||||
|
std::string rest = arg.substr(pos);
|
||||||
|
for (auto c : rest)
|
||||||
|
if (!std::isdigit(c))
|
||||||
|
log_error("weird thing %s\n", rest.c_str());
|
||||||
|
size_t arg_node_idx = std::stoi(rest);
|
||||||
|
log("%zu %zu %s IDX %zu\n", i, j, arg.c_str(), arg_node_idx);
|
||||||
|
// log("%zu %zu %s\n", i, j, arg.c_str());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int sdc_get_pins_cmd(ClientData data, 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[])
|
||||||
{
|
{
|
||||||
auto* objects = (SdcObjects*)data;
|
auto* objects = (SdcObjects*)data;
|
||||||
|
@ -322,19 +410,26 @@ static int sdc_get_pins_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_O
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tcl_Obj *result = Tcl_NewListObj(resolved.size(), nullptr);
|
Tcl_Obj *result = nullptr;
|
||||||
for (auto [name, pin, matching_bits] : resolved) {
|
for (auto [name, pin, matching_bits] : resolved) {
|
||||||
// TODO change this to graph tracking if desired
|
if (objects->value_mode == SdcObjects::ValueMode::Normal) {
|
||||||
size_t width = (size_t)pin.first->getPort(pin.second).size();
|
if (!result)
|
||||||
for (size_t i = 0; i < width; i++)
|
result = Tcl_NewListObj(resolved.size(), nullptr);
|
||||||
if (matching_bits.is_set(i))
|
size_t width = (size_t)pin.first->getPort(pin.second).size();
|
||||||
Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(name.c_str(), name.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->collect_mode != SdcObjects::CollectMode::FullConstraint)
|
if (objects->collect_mode != SdcObjects::CollectMode::FullConstraint)
|
||||||
objects->constrained_pins[std::make_pair(name, pin)].merge(matching_bits);
|
objects->constrained_pins[std::make_pair(name, pin)].merge(matching_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
Tcl_SetObjResult(interp, result);
|
if (objects->value_mode == SdcObjects::ValueMode::Graph) {
|
||||||
|
return redirect_unknown(interp, objc, objv);
|
||||||
|
}
|
||||||
|
if (result)
|
||||||
|
Tcl_SetObjResult(interp, result);
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,6 +588,7 @@ public:
|
||||||
|
|
||||||
objects = std::make_unique<SdcObjects>(design);
|
objects = std::make_unique<SdcObjects>(design);
|
||||||
objects->collect_mode = SdcObjects::CollectMode::SimpleGetter;
|
objects->collect_mode = SdcObjects::CollectMode::SimpleGetter;
|
||||||
|
objects->value_mode = SdcObjects::ValueMode::Graph;
|
||||||
Tcl_CreateObjCommand(interp, "get_pins", sdc_get_pins_cmd, (ClientData) objects.get(), NULL);
|
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, "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);
|
Tcl_CreateObjCommand(interp, "ys_track_typed_key", ys_track_typed_key_cmd, (ClientData) objects.get(), NULL);
|
||||||
|
@ -535,6 +631,7 @@ void execute(std::vector<std::string> args, RTLIL::Design *design) override {
|
||||||
if (Tcl_EvalFile(interp, sdc_path.c_str()) != TCL_OK)
|
if (Tcl_EvalFile(interp, sdc_path.c_str()) != TCL_OK)
|
||||||
log_cmd_error("SDC interpreter returned an error: %s\n", Tcl_GetStringResult(interp));
|
log_cmd_error("SDC interpreter returned an error: %s\n", Tcl_GetStringResult(interp));
|
||||||
sdc.objects->dump();
|
sdc.objects->dump();
|
||||||
|
inspect_globals(interp);
|
||||||
Tcl_Release(interp);
|
Tcl_Release(interp);
|
||||||
}
|
}
|
||||||
} SdcPass;
|
} SdcPass;
|
||||||
|
|
|
@ -13,6 +13,7 @@ stub ys_track_untyped_key
|
||||||
stub ys_err_key
|
stub ys_err_key
|
||||||
stub ys_err_flag
|
stub ys_err_flag
|
||||||
|
|
||||||
|
# TODO move to separate file and tie to graph value mode
|
||||||
proc unknown {args} {
|
proc unknown {args} {
|
||||||
global sdc_call_index
|
global sdc_call_index
|
||||||
global sdc_calls
|
global sdc_calls
|
||||||
|
@ -24,5 +25,9 @@ proc unknown {args} {
|
||||||
}
|
}
|
||||||
incr sdc_call_index
|
incr sdc_call_index
|
||||||
lappend sdc_calls $args
|
lappend sdc_calls $args
|
||||||
return $sdc_call_index
|
puts "unknown $args, returning YOSYS_SDC_MAGIC_NODE_$sdc_call_index"
|
||||||
|
return "YOSYS_SDC_MAGIC_NODE_$sdc_call_index"
|
||||||
|
}
|
||||||
|
proc list {args} {
|
||||||
|
unknown "list" $args
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue