static int shell_cmd_watch(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { const char *help = "watch - Trace changes to a signal\n" "\n" "Usage: watch SIGNALS...\n" "\n" "Prints a message every time an update occurs to a signal listed." "\n" "Examples:\n" " watch [signals {clk}] Trace updates to all signals named clk\n"; if (show_help(objc, objv, help)) return TCL_OK; if (objc == 1) { warnf("nothing to watch (try -help for usage)"); return TCL_OK; } hash_t *decl_hash = (hash_t *)cd; for (int i = 1; i < objc; i++) { int length; if (Tcl_ListObjLength(interp, objv[i], &length) != TCL_OK) return TCL_ERROR; for (int j = 0; j < length; j++) { Tcl_Obj *obj; if (Tcl_ListObjIndex(interp, objv[i], j, &obj) != TCL_OK) return TCL_ERROR; const char *str = Tcl_GetString(obj); tree_t t = hash_get(decl_hash, ident_new(str)); if (t == NULL) return tcl_error(interp, "object not found: %s", str); if (t == NULL) return tcl_error(interp, "object not found: %s", str); else if (tree_kind(t) != T_SIGNAL_DECL) return tcl_error(interp, "not a signal: %s", str); else if (type_is_array(tree_type(t))) return tcl_error(interp, "only scalar signals may be watched"); // TODO: make this work for arrays slave_watch_msg_t msg = { .index = tree_index(t) }; slave_post_msg(SLAVE_WATCH, &msg, sizeof(msg)); } } return TCL_OK; }
static int shell_cmd_unwatch(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { const char *help = "unwatch - Stop tracing signals\n" "\n" "Usage: unwatch SIGNALS...\n" "\n" "Clears any watch callback on SIGNALS. Note this will also stop any\n" "VCD or other waveform capture for these signals.\n" "\n" "Examples:\n" " watch [signals {clk}] Stop tracing updates to clk\n"; if (show_help(objc, objv, help)) return TCL_OK; if (objc == 1) { warnf("nothing to unwatch (try -help for usage)"); return TCL_OK; } hash_t *decl_hash = (hash_t *)cd; // TODO: refactor this code to avoid duplication with "watch" and "show" for (int i = 1; i < objc; i++) { int length; if (Tcl_ListObjLength(interp, objv[i], &length) != TCL_OK) return TCL_ERROR; for (int j = 0; j < length; j++) { Tcl_Obj *obj; if (Tcl_ListObjIndex(interp, objv[i], j, &obj) != TCL_OK) return TCL_ERROR; const char *str = Tcl_GetString(obj); tree_t t = hash_get(decl_hash, ident_new(str)); if (t == NULL) return tcl_error(interp, "object not found: %s", str); else if (tree_kind(t) != T_SIGNAL_DECL) return tcl_error(interp, "not a signal: %s", str); slave_unwatch_msg_t msg = { .index = tree_index(t) }; slave_post_msg(SLAVE_UNWATCH, &msg, sizeof(msg)); } } return TCL_OK; }
static int shell_cmd_run(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { static bool sim_running = false; if (sim_running) return tcl_error(interp, "simulation already running"); uint64_t stop_time = UINT64_MAX; if (objc == 3) { Tcl_WideInt base; int error = Tcl_GetWideIntFromObj(interp, objv[1], &base); if (error != TCL_OK || base <= 0) return tcl_error(interp, "invalid time"); const char *unit = Tcl_GetString(objv[2]); uint64_t mult; if (strcmp(unit, "fs") == 0) mult = 1; else if (strcmp(unit, "ps") == 0) mult = 1000; else if (strcmp(unit, "ns") == 0) mult = 1000000; else if (strcmp(unit, "us") == 0) mult = 1000000000; else if (strcmp(unit, "ms") == 0) mult = 1000000000000; else { fprintf(stderr, "invalid time unit %s", unit); return TCL_ERROR; } stop_time = rt_now(NULL) + (base * mult); } else if (objc != 1) return tcl_error(interp, "usage: run [time units]"); sim_running = true; rt_run_interactive(stop_time); sim_running = false; return TCL_OK; }
static int shell_cmd_now(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { const char *help = "now - Display current simulation time\n" "\n" "Usage: now [-q]\n" "\n" "Prints the current simulation time to the standard output unless -q\n" "is specified. Returns the time as a string.\n" "\n" "Examples:\n" " now Print current time\n" " set n [now -q] Store current time in a variable\n"; if (show_help(objc, objv, help)) return TCL_OK; bool quiet = false; for (int i = 1; i < objc; i++) { const char *what = Tcl_GetString(objv[i]); if (strcmp(what, "-q") == 0) quiet = true; else return tcl_error(interp, "invalid argument '%s' " "(try -help for usage)", what); } slave_post_msg(SLAVE_NOW, NULL, 0); reply_now_msg_t reply; slave_get_reply(REPLY_NOW, &reply, sizeof(reply)); if (!quiet) printf("%s\n", reply.text); Tcl_SetObjResult(interp, Tcl_NewIntObj(reply.now)); return TCL_OK; }
static int shell_cmd_now(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { const char *help = "now - Display current simulation time\n" "\n" "Usage: now [-q]\n" "\n" "Prints the current simulation time to the standard output unless -q\n" "is specified. Returns the time as a string.\n" "\n" "Examples:\n" " now Print current time\n" " set n [now -q] Store current time in a variable\n"; if (show_help(objc, objv, help)) return TCL_OK; bool quiet = false; for (int i = 1; i < objc; i++) { const char *what = Tcl_GetString(objv[i]); if (strcmp(what, "-q") == 0) quiet = true; else return tcl_error(interp, "invalid argument '%s' " "(try -help for usage)", what); } const uint64_t now = rt_now(NULL); if (!quiet) printf("%s\n", fmt_time(now)); Tcl_SetObjResult(interp, Tcl_NewIntObj(now)); return TCL_OK; }
static int shell_cmd_show(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { const char *help = "show - Display simulation objects\n" "\n" "Usage: show LIST...\n" "\n" "Prints a representation of each simulation object in LIST. Typically\n" "this will be a list of signal names and the output will show their\n" "current value.\n" "\n" "Examples:\n" " show {:top:foo} Print value of signal :top_foo\n" " show [signals] Print value of all signals\n"; if (show_help(objc, objv, help)) return TCL_OK; if (objc == 1) { warnf("nothing to show (try -help for usage)"); return TCL_OK; } hash_t *decl_hash = (hash_t *)cd; for (int i = 1; i < objc; i++) { int length; if (Tcl_ListObjLength(interp, objv[i], &length) != TCL_OK) return TCL_ERROR; for (int j = 0; j < length; j++) { Tcl_Obj *obj; if (Tcl_ListObjIndex(interp, objv[i], j, &obj) != TCL_OK) return TCL_ERROR; const char *str = Tcl_GetString(obj); tree_t t = hash_get(decl_hash, ident_new(str)); if (t == NULL) return tcl_error(interp, "object not found: %s", str); tree_kind_t kind = tree_kind(t); switch (kind) { case T_SIGNAL_DECL: { const size_t len = tree_nets(t); uint64_t *values LOCAL = xmalloc(len * sizeof(uint64_t)); rt_signal_value(t, values, len); const char *type_str = type_pp(tree_type(t)); const char *short_name = strrchr(type_str, '.'); LOCAL_TEXT_BUF values_tb = pprint(t, values, len); printf("%-30s%-20s%s\n", str, (short_name != NULL ? short_name + 1 : type_str), tb_get(values_tb)); } break; default: return tcl_error(interp, "cannot show tree kind %s", tree_kind_str(kind)); } } } return TCL_OK; }
static int shell_cmd_show(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { const char *help = "show - Display simulation objects\n" "\n" "Usage: show LIST...\n" "\n" "Prints a representation of each simulation object in LIST. Typically\n" "this will be a list of signal names and the output will show their\n" "current value.\n" "\n" "Examples:\n" " show {:top:foo} Print value of signal :top_foo\n" " show [signals] Print value of all signals\n"; if (show_help(objc, objv, help)) return TCL_OK; if (objc == 1) { warnf("nothing to show (try -help for usage)"); return TCL_OK; } hash_t *decl_hash = (hash_t *)cd; for (int i = 1; i < objc; i++) { int length; if (Tcl_ListObjLength(interp, objv[i], &length) != TCL_OK) return TCL_ERROR; for (int j = 0; j < length; j++) { Tcl_Obj *obj; if (Tcl_ListObjIndex(interp, objv[i], j, &obj) != TCL_OK) return TCL_ERROR; const char *str = Tcl_GetString(obj); tree_t t = hash_get(decl_hash, ident_new(str)); if (t == NULL) return tcl_error(interp, "object not found: %s", str); tree_kind_t kind = tree_kind(t); switch (kind) { case T_SIGNAL_DECL: { size_t len = 1; type_t type = tree_type(t); while (type_is_array(type)) { int64_t low = 0, high = 0; range_bounds(type_dim(type, 0), &low, &high); len *= (high - low + 1); type = type_elem(type); } slave_read_signal_msg_t msg = { .index = tree_index(t), .len = len }; slave_post_msg(SLAVE_READ_SIGNAL, &msg, sizeof(msg)); const size_t rsz = sizeof(reply_read_signal_msg_t) + (msg.len * sizeof(uint64_t)); reply_read_signal_msg_t *reply = xmalloc(rsz); slave_get_reply(REPLY_READ_SIGNAL, reply, rsz); const char *type_str = type_pp(type); const char *short_name = strrchr(type_str, '.'); printf("%-30s%-20s%s\n", str, (short_name != NULL ? short_name + 1 : type_str), pprint(t, reply->values, msg.len)); free(reply); } break; default: return tcl_error(interp, "cannot show tree kind %s", tree_kind_str(kind)); } } } return TCL_OK; }