aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/yosys.cc
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/yosys.cc')
-rw-r--r--kernel/yosys.cc96
1 files changed, 90 insertions, 6 deletions
diff --git a/kernel/yosys.cc b/kernel/yosys.cc
index 01085d29b..333faae6a 100644
--- a/kernel/yosys.cc
+++ b/kernel/yosys.cc
@@ -73,6 +73,8 @@
#include <limits.h>
#include <errno.h>
+#include "libs/json11/json11.hpp"
+
YOSYS_NAMESPACE_BEGIN
int autoidx = 1;
@@ -82,6 +84,7 @@ CellTypes yosys_celltypes;
#ifdef YOSYS_ENABLE_TCL
Tcl_Interp *yosys_tcl_interp = NULL;
+bool yosys_tcl_repl_active = false;
#endif
std::set<std::string> yosys_input_files, yosys_output_files;
@@ -709,6 +712,42 @@ void rewrite_filename(std::string &filename)
}
#ifdef YOSYS_ENABLE_TCL
+
+static Tcl_Obj *json_to_tcl(Tcl_Interp *interp, const json11::Json &json)
+{
+ if (json.is_null())
+ return Tcl_NewStringObj("null", 4);
+ else if (json.is_string()) {
+ auto string = json.string_value();
+ return Tcl_NewStringObj(string.data(), string.size());
+ } else if (json.is_number()) {
+ double value = json.number_value();
+ double round_val = std::nearbyint(value);
+ if (std::isfinite(round_val) && value == round_val && value >= LONG_MIN && value < -double(LONG_MIN))
+ return Tcl_NewLongObj((long)round_val);
+ else
+ return Tcl_NewDoubleObj(value);
+ } else if (json.is_bool()) {
+ return Tcl_NewBooleanObj(json.bool_value());
+ } else if (json.is_array()) {
+ auto list = json.array_items();
+ Tcl_Obj *result = Tcl_NewListObj(list.size(), nullptr);
+ for (auto &item : list)
+ Tcl_ListObjAppendElement(interp, result, json_to_tcl(interp, item));
+ return result;
+ } else if (json.is_object()) {
+ auto map = json.object_items();
+ Tcl_Obj *result = Tcl_NewListObj(map.size() * 2, nullptr);
+ for (auto &item : map) {
+ Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(item.first.data(), item.first.size()));
+ Tcl_ListObjAppendElement(interp, result, json_to_tcl(interp, item.second));
+ }
+ return result;
+ } else {
+ log_abort();
+ }
+}
+
static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *argv[])
{
std::vector<std::string> args;
@@ -733,12 +772,52 @@ static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *a
return TCL_OK;
}
- if (args.size() == 1) {
- Pass::call(yosys_get_design(), args[0]);
- return TCL_OK;
+ yosys_get_design()->scratchpad_unset("result.json");
+ yosys_get_design()->scratchpad_unset("result.string");
+
+ bool in_repl = yosys_tcl_repl_active;
+ bool restore_log_cmd_error_throw = log_cmd_error_throw;
+
+ log_cmd_error_throw = true;
+
+ try {
+ if (args.size() == 1) {
+ Pass::call(yosys_get_design(), args[0]);
+ } else {
+ Pass::call(yosys_get_design(), args);
+ }
+ } catch (log_cmd_error_exception) {
+ if (in_repl) {
+ auto design = yosys_get_design();
+ while (design->selection_stack.size() > 1)
+ design->selection_stack.pop_back();
+ log_reset_stack();
+ }
+ Tcl_SetResult(interp, (char *)"Yosys command produced an error", TCL_STATIC);
+
+ yosys_tcl_repl_active = in_repl;
+ log_cmd_error_throw = restore_log_cmd_error_throw;
+ return TCL_ERROR;
+ } catch (...) {
+ log_error("uncaught exception during Yosys command invoked from TCL\n");
+ }
+
+ yosys_tcl_repl_active = in_repl;
+ log_cmd_error_throw = restore_log_cmd_error_throw;
+
+ auto &scratchpad = yosys_get_design()->scratchpad;
+ auto result = scratchpad.find("result.json");
+ if (result != scratchpad.end()) {
+ std::string err;
+ auto json = json11::Json::parse(result->second, err);
+ if (err.empty()) {
+ Tcl_SetObjResult(interp, json_to_tcl(interp, json));
+ } else
+ log_warning("Ignoring result.json scratchpad value due to parse error: %s\n", err.c_str());
+ } else if ((result = scratchpad.find("result.string")) != scratchpad.end()) {
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(result->second.data(), result->second.size()));
}
- Pass::call(yosys_get_design(), args);
return TCL_OK;
}
@@ -750,6 +829,11 @@ int yosys_tcl_iterp_init(Tcl_Interp *interp)
return TCL_OK ;
}
+void yosys_tcl_activate_repl()
+{
+ yosys_tcl_repl_active = true;
+}
+
extern Tcl_Interp *yosys_get_tcl_interp()
{
if (yosys_tcl_interp == NULL) {
@@ -778,8 +862,8 @@ struct TclPass : public Pass {
log("the standard $argc and $argv variables.\n");
log("\n");
log("Note, tcl will not recieve the output of any yosys command. If the output\n");
- log("of the tcl commands are needed, use the yosys command 'tee' to redirect yosys's\n");
- log("output to a temporary file.\n");
+ log("of the tcl commands are needed, use the yosys command 'tee -s result.string'\n");
+ log("to redirect yosys's output to the 'result.string' scratchpad value.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *) override {