From f0e9a35eb6f8376b8056c6d09d3da404d25cc8c5 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 7 Jan 2022 11:53:32 +0100 Subject: [PATCH] Add 'esave' command to save only specific event nodes. Add a prompt for esave/eprint/eprvcd. --- src/frontend/arg.c | 34 +++++++++++++- src/frontend/arg.h | 1 + src/frontend/commands.c | 8 +++- src/include/ngspice/evt.h | 1 + src/include/ngspice/evtproto.h | 3 +- src/xspice/evt/evtaccept.c | 23 +++++++-- src/xspice/evt/evtprint.c | 86 ++++++++++++++++++++++++++++++---- src/xspice/evt/evttermi.c | 1 + 8 files changed, 139 insertions(+), 18 deletions(-) diff --git a/src/frontend/arg.c b/src/frontend/arg.c index dcd07e5b4..bb79bc016 100644 --- a/src/frontend/arg.c +++ b/src/frontend/arg.c @@ -18,7 +18,9 @@ Author: 1987 Jeffrey M. Hsu static void common(const char *string, const struct wordlist *wl, - const struct comm *command); + const struct comm *command); +static void common_list(const char *string, const struct wordlist *wl, + const struct comm *command); static int countargs(const wordlist *wl); @@ -108,6 +110,12 @@ void arg_display(const wordlist *wl, const struct comm *command) } +void arg_enodes(const wordlist *wl, const struct comm *command) +{ + common_list("which event nodes", wl, command); +} + + /* a common prompt routine */ static void common(const char *string, const struct wordlist *wl, const struct comm *command) @@ -129,6 +137,30 @@ static void common(const char *string, const struct wordlist *wl, } /* end of function common */ +/* A common prompt routine for commands that take a list. */ +static void common_list(const char *string, const struct wordlist *wl, + const struct comm *command) +{ + struct wordlist *w; + char *buf; + + if (!countargs(wl)) { + outmenuprompt(string); + if ((buf = prompt(cp_in)) == NULL) /* prompt aborted */ + return; /* don't execute command */ + /* do something with the wordlist */ + w = cp_lexer(buf); + if (!w) + return; + if (w->wl_word) { + /* O.K. now call fn */ + command->co_func(w); + } + wl_free(w); + } +} + + void outmenuprompt(const char *string) { diff --git a/src/frontend/arg.h b/src/frontend/arg.h index 7c049b45d..e65e466d2 100644 --- a/src/frontend/arg.h +++ b/src/frontend/arg.h @@ -14,6 +14,7 @@ void arg_load(const wordlist *wl, const struct comm *command); void arg_let(const wordlist *wl, const struct comm *command); void arg_set(const wordlist *wl, const struct comm *command); void arg_display(const wordlist *wl, const struct comm *command); +void arg_enodes(const wordlist *wl, const struct comm *command); void outmenuprompt(const char *string); diff --git a/src/frontend/commands.c b/src/frontend/commands.c index a2bee452b..623ccf376 100644 --- a/src/frontend/commands.c +++ b/src/frontend/commands.c @@ -247,13 +247,17 @@ struct comm spcp_coms[] = { arg_print, "[col] expr ... : Print vector values." } , #ifdef XSPICE + { "esave", EVTsave, FALSE, TRUE, + { 040000, 040000, 040000, 040000 }, E_BEGINNING, 1, LOTS, + arg_enodes, + "all | none | node node ... : Save event values." } , { "eprint", EVTprint, FALSE, TRUE, { 040000, 040000, 040000, 040000 }, E_BEGINNING, 1, LOTS, - NULL, + arg_enodes, "node node ... : Print event values." } , { "eprvcd", EVTprintvcd, FALSE, TRUE, { 040000, 040000, 040000, 040000 }, E_BEGINNING, 1, LOTS, - NULL, + arg_enodes, "node node ... : Print event values into vcd file." }, { "edisplay", EVTdisplay, FALSE, TRUE, { 040000, 040000, 040000, 040000 }, E_BEGINNING, 0, 0, diff --git a/src/include/ngspice/evt.h b/src/include/ngspice/evt.h index a9f46c600..2917b76a5 100644 --- a/src/include/ngspice/evt.h +++ b/src/include/ngspice/evt.h @@ -83,6 +83,7 @@ struct Evt_Node_Info { char *name; /* Name of node in deck */ int udn_index; /* Index of the node type */ Mif_Boolean_t invert; /* True if need to make inverted copy */ + Mif_Boolean_t save; /* Save data for this node */ int num_ports; /* Number of ports connected to this node */ int num_outputs; /* Number of outputs connected to this node */ int num_insts; /* The number of insts receiving node as input */ diff --git a/src/include/ngspice/evtproto.h b/src/include/ngspice/evtproto.h index a961db1da..384766369 100644 --- a/src/include/ngspice/evtproto.h +++ b/src/include/ngspice/evtproto.h @@ -95,9 +95,8 @@ void EVTdequeue(CKTcircuit *ckt, double time); int EVTload(CKTcircuit *ckt, int inst_index); void EVTprint(wordlist *wl); - void EVTprintvcd(wordlist *wl); - +void EVTsave(wordlist *wl); void EVTdisplay(wordlist *wl); int EVTop( diff --git a/src/xspice/evt/evtaccept.c b/src/xspice/evt/evtaccept.c index 497a83c7c..b3226efdb 100644 --- a/src/xspice/evt/evtaccept.c +++ b/src/xspice/evt/evtaccept.c @@ -70,7 +70,7 @@ void EVTaccept( Evt_Inst_Queue_t *inst_queue; Evt_Output_Queue_t *output_queue; - + Evt_Node_Info_t **node_table; Evt_Node_Data_t *node_data; Evt_State_Data_t *state_data; Evt_Msg_Data_t *msg_data; @@ -83,7 +83,7 @@ void EVTaccept( /* Get often used pointers */ inst_queue = &(ckt->evt->queue.inst); output_queue = &(ckt->evt->queue.output); - + node_table = ckt->evt->info.node_table; node_data = ckt->evt->data.node; state_data = ckt->evt->data.state; msg_data = ckt->evt->data.msg; @@ -161,10 +161,25 @@ void EVTaccept( for(i = 0; i < num_modified; i++) { /* Get the index of the node modified */ index = node_data->modified_index[i]; - /* Update last_step for this index */ - node_data->last_step[index] = node_data->tail[index]; /* Reset the modified flag */ node_data->modified[index] = MIF_FALSE; + + if (node_table[index]->save) { + /* Update last_step for this index */ + node_data->last_step[index] = node_data->tail[index]; + } else { + Evt_Node_t *keep; + + /* If not recording history, discard all but the last item. + * It may be needed to restore the previous state on backup. + */ + keep = *(node_data->tail[index]); + *(node_data->tail[index]) = node_data->free[index]; + node_data->free[index] = node_data->head[index]; + node_data->head[index] = keep; + node_data->last_step[index] = node_data->tail[index] = + &node_data->head[index]; + } } /* Reset number modified to zero */ node_data->num_modified = 0; diff --git a/src/xspice/evt/evtprint.c b/src/xspice/evt/evtprint.c index 112f1fcbc..cfc51bb8a 100644 --- a/src/xspice/evt/evtprint.c +++ b/src/xspice/evt/evtprint.c @@ -413,12 +413,15 @@ EVTdisplay(wordlist *wl) out_printf("No event node available!\n"); return; } - if (!ckt->evt->jobs.job_plot) { - out_printf("No event job run, no data available!\n"); - return; + if (ckt->evt->jobs.job_plot) { + out_printf("\nList of event nodes in plot %s\n", + ckt->evt->jobs.job_plot[ckt->evt->jobs.cur_job]); + } else { + out_printf("\nList of event nodes\n"); } - out_printf("\nList of event nodes in plot %s\n", ckt->evt->jobs.job_plot[ckt->evt->jobs.cur_job]); - out_printf(" %-20s: %-5s, %s\n\n", "node name", "type", "number of events"); + out_printf(" %-20s: %-5s, %s\n\n", + "node name", "type", "number of events"); + node_index = 0; while (node) { Evt_Node_t *node_data = NULL; @@ -426,11 +429,12 @@ EVTdisplay(wordlist *wl) char *type; udn_index = node_table[node_index]->udn_index; - if (ckt->evt->data.node) + if (ckt->evt->data.node) { node_data = ckt->evt->data.node->head[node_index]; - while (node_data) { - count++; - node_data = node_data->next; + while (node_data) { + count++; + node_data = node_data->next; + } } type = g_evt_udn_info[udn_index]->name; out_printf(" %-20s: %-5s, %5d\n", node->name, type, count); @@ -710,3 +714,67 @@ EVTprintvcd(wordlist *wl) out_printf("\n\n"); } + +/* Mark event nodes whose data should be saved for printing. + * By default, all nodes are saved, so initial "none" clears. + */ + +static void set_all(CKTcircuit *ckt, Mif_Boolean_t val) +{ + int i, count; + Evt_Node_Info_t **node_table; + + count = ckt->evt->counts.num_nodes; + node_table = ckt->evt->info.node_table; + for (i = 0; i < count; i++) + node_table[i]->save = val; +} + +void +EVTsave(wordlist *wl) +{ + int i; + Mif_Boolean_t save; + wordlist *w; + CKTcircuit *ckt; + Evt_Node_Info_t **node_table; + + if (wl == NULL) { + printf("Usage: esave all | none | ...\n"); + return; + } + + /* Get needed pointers. */ + + ckt = g_mif_info.ckt; + if (!ckt) { + fprintf(cp_err, "Error: no circuit loaded.\n"); + return; + } + node_table = ckt->evt->info.node_table; + + /* Deal with "all" and "none". */ + + save = MIF_FALSE; + if (wl->wl_next == NULL && + (!strcmp("none", wl->wl_word) || + (save = !strcmp("all", wl->wl_word)))) { + set_all(ckt, save); + return; + } + + set_all(ckt, MIF_FALSE); /* Clear previous settings. */ + + /* Set save flag for each argument */ + + for (w = wl; w; w = w->wl_next) { + i = get_index(w->wl_word); + if (i < 0) { + fprintf(cp_err, "ERROR - Node %s is not an event node.\n", + w->wl_word); + return; + } +// node_table[i]->save = MIF_FALSE; + node_table[i]->save = MIF_TRUE; + } +} diff --git a/src/xspice/evt/evttermi.c b/src/xspice/evt/evttermi.c index f2f0b2452..5f591ccef 100644 --- a/src/xspice/evt/evttermi.c +++ b/src/xspice/evt/evttermi.c @@ -329,6 +329,7 @@ static void EVTnode_insert( node->next = NULL; node->name = MIFcopy(node_name); node->udn_index = udn_index; + node->save = MIF_TRUE; /* Backward compatible behaviour: save all. */ index = ckt->evt->counts.num_nodes; (ckt->evt->counts.num_nodes)++; }