From ccd98d21c1e531b01b21955eefae0219528602c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 16 Oct 2024 11:43:02 +0200 Subject: [PATCH] Start Tcl design inspection methods --- kernel/yosys.cc | 298 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 298 insertions(+) diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 374b07d06..ca6f0c480 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -829,11 +829,309 @@ static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *a return TCL_OK; } +#define FLAG(name) \ + if (!strcmp(argv[i], "-" #name)) { \ + name##_flag = true; \ + continue; \ + } \ + +#define ERROR(str) \ + { \ + Tcl_SetResult(interp, (char *)(str), TCL_STATIC); \ + return TCL_ERROR; \ + } + +static int tcl_get_attr(ClientData, Tcl_Interp *interp, int argc, const char *argv[]) +{ + int i; + bool mod_flag = false, string_flag = false, int_flag = false, bool_flag = false; + for (i = 1; i < argc; i++) { + FLAG(mod) + FLAG(string) + FLAG(int) + FLAG(bool) + break; + } + + if ((mod_flag && i != argc - 2) || + (!mod_flag && i != argc - 3) || + (string_flag + int_flag + bool_flag > 1)) + ERROR("bad usage: expected \"get_attr -mod [-string|-int|-bool] \"" + " or \"get_attr [-string|-int|-bool] \"") + + IdString mod_id, obj_id, attr_id; + mod_id = RTLIL::escape_id(argv[i++]); + if (!mod_flag) + obj_id = RTLIL::escape_id(argv[i++]); + attr_id = RTLIL::escape_id(argv[i++]); + + RTLIL::Module *mod = yosys_design->module(mod_id); + if (!mod) + ERROR("module not found") + + RTLIL::AttrObject *obj = nullptr; + if (mod_flag) { + obj = mod; + } else { + obj = mod->wire(obj_id); + if (!obj) + obj = mod->memories.at(obj_id, nullptr); + if (!obj) + obj = mod->cell(obj_id); + if (!obj) + obj = mod->processes.at(obj_id, nullptr); + } + + if (!obj) + ERROR("object not found") + + if (string_flag) { + Tcl_SetResult(interp, (char *) obj->get_string_attribute(attr_id).c_str(), TCL_VOLATILE); + } else if (int_flag) { + if (!obj->has_attribute(attr_id)) + ERROR("attribute missing (required for -int)"); + + RTLIL::Const &value = obj->attributes.at(attr_id); + if (value.size() > 32) + ERROR("value too large") + + // FIXME: 32'hffffffff will return as negative despite is_signed=false + Tcl_SetResult(interp, (char *) std::to_string(value.as_int()).c_str(), TCL_VOLATILE); + } else if (bool_flag) { + bool value = obj->get_bool_attribute(attr_id); + Tcl_SetResult(interp, (char *) std::to_string(value).c_str(), TCL_VOLATILE); + } else { + if (!obj->has_attribute(attr_id)) + ERROR("attribute missing (required unless -bool or -string)") + + Tcl_SetResult(interp, (char *) obj->attributes.at(attr_id).as_string().c_str(), TCL_VOLATILE); + } + + return TCL_OK; +} + +static int tcl_has_attr(ClientData, Tcl_Interp *interp, int argc, const char *argv[]) +{ + int i; + bool mod_flag = false; + for (i = 1; i < argc; i++) { + FLAG(mod) + break; + } + + if ((mod_flag && i != argc - 2) || + (!mod_flag && i != argc - 3)) + ERROR("bad usage: expected \"has_attr -mod \"" + " or \"has_attr \"") + + IdString mod_id, obj_id, attr_id; + mod_id = RTLIL::escape_id(argv[i++]); + if (!mod_flag) + obj_id = RTLIL::escape_id(argv[i++]); + attr_id = RTLIL::escape_id(argv[i++]); + + RTLIL::Module *mod = yosys_design->module(mod_id); + if (!mod) + ERROR("module not found") + + RTLIL::AttrObject *obj = nullptr; + if (mod_flag) { + obj = mod; + } else { + obj = mod->wire(obj_id); + if (!obj) + obj = mod->memories.at(obj_id, nullptr); + if (!obj) + obj = mod->cell(obj_id); + if (!obj) + obj = mod->processes.at(obj_id, nullptr); + } + + if (!obj) + ERROR("object not found") + + Tcl_SetResult(interp, (char *) std::to_string(obj->has_attribute(attr_id)).c_str(), TCL_VOLATILE); + return TCL_OK; +} + +static int tcl_set_attr(ClientData, Tcl_Interp *interp, int argc, const char *argv[]) +{ + int i; + bool mod_flag = false, string_flag = false, int_flag = false, bool_flag = false; + bool false_flag = false, true_flag = false; + for (i = 1; i < argc; i++) { + FLAG(mod) + FLAG(string) + FLAG(int) + FLAG(bool) + FLAG(false) + FLAG(true) + break; + } + + if ((i != argc - (2 + !mod_flag + !(true_flag || false_flag))) || + (string_flag + int_flag + bool_flag + true_flag + false_flag > 1)) + ERROR("bad usage: expected \"set_attr -mod [-string|-int|-bool] \"" + " or \"set_attr [-string|-int|-bool] \"" + " or \"set_attr [-true|-false] \"" + " or \"set_attr -mod [-true|-false| \"") + + IdString mod_id, obj_id, attr_id; + mod_id = RTLIL::escape_id(argv[i++]); + if (!mod_flag) + obj_id = RTLIL::escape_id(argv[i++]); + attr_id = RTLIL::escape_id(argv[i++]); + + RTLIL::Module *mod = yosys_design->module(mod_id); + if (!mod) + ERROR("module not found") + + RTLIL::AttrObject *obj = nullptr; + if (mod_flag) { + obj = mod; + } else { + obj = mod->wire(obj_id); + if (!obj) + obj = mod->memories.at(obj_id, nullptr); + if (!obj) + obj = mod->cell(obj_id); + if (!obj) + obj = mod->processes.at(obj_id, nullptr); + } + + if (!obj) + ERROR("object not found") + + if (string_flag) { + obj->set_string_attribute(attr_id, argv[i++]); + } else if (int_flag) { + obj->attributes[attr_id] = atoi(argv[i++]); + } else if (bool_flag) { + obj->set_bool_attribute(attr_id, atoi(argv[i++]) != 0); + } else if (true_flag) { + obj->set_bool_attribute(attr_id, true); + } else if (false_flag) { + obj->set_bool_attribute(attr_id, false); + } else { + obj->attributes[attr_id] = Const::from_string(std::string(argv[i++])); + } + + return TCL_OK; +} + +static int tcl_get_param(ClientData, Tcl_Interp *interp, int argc, const char *argv[]) +{ + int i; + bool string_flag = false, int_flag = false; + for (i = 1; i < argc; i++) { + FLAG(string) + FLAG(int) + break; + } + + if ((i != argc - 3) || + (string_flag + int_flag > 1)) + ERROR("bad usage: expected \"get_param [-string|-int] ") + + IdString mod_id, cell_id, param_id; + mod_id = RTLIL::escape_id(argv[i++]); + cell_id = RTLIL::escape_id(argv[i++]); + param_id = RTLIL::escape_id(argv[i++]); + + RTLIL::Module *mod = yosys_design->module(mod_id); + if (!mod) + ERROR("module not found") + + RTLIL::Cell *cell = mod->cell(cell_id); + if (!cell) + ERROR("object not found") + + if (!cell->hasParam(param_id)) + ERROR("parameter missing") + + const RTLIL::Const &value = cell->getParam(param_id); + + if (string_flag) { + Tcl_SetResult(interp, (char *) value.decode_string().c_str(), TCL_VOLATILE); + } else if (int_flag) { + if (value.size() > 32) + ERROR("value too large") + + Tcl_SetResult(interp, (char *) std::to_string(value.as_int()).c_str(), TCL_VOLATILE); + } else { + Tcl_SetResult(interp, (char *) value.as_string().c_str(), TCL_VOLATILE); + } + return TCL_OK; +} + +static int tcl_set_param(ClientData, Tcl_Interp *interp, int argc, const char *argv[]) +{ + int i; + bool string_flag = false, int_flag = false; + for (i = 1; i < argc; i++) { + FLAG(string) + FLAG(int) + break; + } + + if ((i != argc - 4) || + (string_flag + int_flag > 1)) + ERROR("bad usage: expected \"get_param [-string|-int] ") + + IdString mod_id, cell_id, param_id; + mod_id = RTLIL::escape_id(argv[i++]); + cell_id = RTLIL::escape_id(argv[i++]); + param_id = RTLIL::escape_id(argv[i++]); + + RTLIL::Module *mod = yosys_design->module(mod_id); + if (!mod) + ERROR("module not found") + + RTLIL::Cell *cell = mod->cell(cell_id); + if (!cell) + ERROR("object not found") + + if (string_flag) { + cell->setParam(param_id, Const(std::string(argv[i++]))); + } else if (int_flag) { + cell->setParam(param_id, Const(atoi(argv[i++]))); + } else { + cell->setParam(param_id, Const::from_string(std::string(argv[i++]))); + } + return TCL_OK; +} + int yosys_tcl_iterp_init(Tcl_Interp *interp) { if (Tcl_Init(interp)!=TCL_OK) log_warning("Tcl_Init() call failed - %s\n",Tcl_ErrnoMsg(Tcl_GetErrno())); Tcl_CreateCommand(interp, "yosys", tcl_yosys_cmd, NULL, NULL); + Tcl_CreateCommand(interp, "rtlil::get_attr", tcl_get_attr, NULL, NULL); + Tcl_CreateCommand(interp, "rtlil::has_attr", tcl_has_attr, NULL, NULL); + Tcl_CreateCommand(interp, "rtlil::set_attr", tcl_set_attr, NULL, NULL); + Tcl_CreateCommand(interp, "rtlil::get_param", tcl_get_param, NULL, NULL); + Tcl_CreateCommand(interp, "rtlil::set_param", tcl_set_param, NULL, NULL); + + // TODO: + // + // port_list + // wire_list + // cell_list + // wire_width + // + // add_wire + // add_cell + // rename_wire + // rename_cell + // remove + // + // SigSpec land + // + // get_conn + // set_conn + // unpack + // pack + return TCL_OK ; }