Fix the debugger to finish correctly.
[iverilog.git] / vvp / stop.cc
blobc1fdb312505ef5b30a8826b67fc784c9edb6187d
1 /*
2 * Copyright (c) 2003 Stephen Williams (steve@icarus.com)
4 * This source code is free software; you can redistribute it
5 * and/or modify it in source code form under the terms of the GNU
6 * General Public License as published by the Free Software
7 * Foundation; either version 2 of the License, or (at your option)
8 * any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 #ifdef HAVE_CVS_IDENT
20 #ident "$Id: stop.cc,v 1.16 2006/06/18 04:15:50 steve Exp $"
21 #endif
24 * This file provides a simple command line debugger for the vvp
25 * runtime. It is a means to interact with the user running the
26 * simulation.
29 # include "config.h"
32 # include "vpi_priv.h"
33 # include "vthread.h"
34 # include "schedule.h"
35 # include <stdio.h>
36 # include <ctype.h>
37 #ifdef HAVE_READLINE_READLINE_H
38 # include <readline/readline.h>
39 #endif
40 #ifdef HAVE_READLINE_HISTORY_H
41 # include <readline/history.h>
42 #endif
43 # include <string.h>
44 # include <stdlib.h>
45 #ifdef HAVE_MALLOC_H
46 # include <malloc.h>
47 #endif
49 struct __vpiScope*stop_current_scope = 0;
51 #ifndef USE_READLINE
52 static char* readline_stub(const char*prompt)
54 char buf[256];
56 if (prompt && prompt[0]) {
57 fputs(prompt, stdout);
58 fflush(stdout);
61 if (fgets(buf, sizeof(buf), stdin)) {
62 char*nl = buf + strlen(buf);
63 while (nl > buf && isspace(nl[-1])) {
64 nl -= 1;
65 nl[0] = 0;
68 return strdup(buf);
71 return 0;
73 #define readline(x) readline_stub(x)
74 #endif
77 static bool interact_flag = true;
79 static void cmd_call(unsigned argc, char*argv[])
81 struct __vpiHandle**table;
82 unsigned ntable;
84 if (stop_current_scope == 0) {
85 vpip_make_root_iterator(table, ntable);
87 } else {
88 table = stop_current_scope->intern;
89 ntable = stop_current_scope->nintern;
92 /* This is an array of vpiHandles, for passing to the created
93 command. */
94 unsigned vpi_argc = argc - 1;
95 vpiHandle*vpi_argv = (vpiHandle*)calloc(vpi_argc, sizeof(vpiHandle));
96 vpiHandle*vpi_free = (vpiHandle*)calloc(vpi_argc, sizeof(vpiHandle));
98 unsigned errors = 0;
100 for (unsigned idx = 0 ; idx < vpi_argc ; idx += 1) {
101 vpiHandle handle = 0;
102 bool add_to_free_list = false;
104 /* Detect the special case that the argument is the
105 .(dot) string. This represents the handle for the
106 current scope. */
107 if (stop_current_scope && (strcmp(argv[idx+1], ".") == 0))
108 handle = &stop_current_scope->base;
110 /* Is the argument a quoted string? */
111 if (handle == 0 && argv[idx+1][0] == '"') {
112 char*tmp = strdup(argv[idx+1]);
113 tmp[strlen(tmp)-1] = 0;
115 /* Create a temporary vpiStringConst to pass as a
116 handle. Make it temporary so that memory is
117 reclaimed after the call is completed. */
118 handle = vpip_make_string_const(strdup(tmp+1), false);
119 add_to_free_list = true;
120 free(tmp);
123 /* Is the argument a decimal constant? */
124 if (handle == 0
125 && strspn(argv[idx+1],"0123456789") == strlen(argv[idx+1])) {
126 handle = vpip_make_dec_const(strtol(argv[idx+1],0,10));
127 add_to_free_list = true;
130 /* Try to find the vpiHandle within this scope that has
131 the name in argv[idx+2]. Look in the current scope. */
133 for (unsigned tmp = 0 ; (tmp < ntable)&& !handle ; tmp += 1) {
134 struct __vpiScope*scope;
135 const char*name;
137 switch (table[tmp]->vpi_type->type_code) {
139 case vpiModule:
140 case vpiFunction:
141 case vpiTask:
142 case vpiNamedBegin:
143 case vpiNamedFork:
144 scope = (struct __vpiScope*) table[idx];
145 if (strcmp(scope->name, argv[idx+1]) == 0)
146 handle = table[tmp];
147 break;
149 case vpiReg:
150 case vpiNet:
151 case vpiParameter:
152 name = vpi_get_str(vpiName,table[tmp]);
153 if (strcmp(argv[idx+1], name) == 0)
154 handle = table[tmp];
155 break;
159 if (handle == 0) {
160 printf("call error: I don't know how to"
161 " pass %s to %s\n", argv[idx+1], argv[0]);
162 errors += 1;
165 vpi_argv[idx] = handle;
166 if (add_to_free_list)
167 vpi_free[idx] = handle;
168 else
169 vpi_free[idx] = 0;
173 /* If there are no errors so far, then make up a call to the
174 vpi task and execute that call. Free the call structure
175 when we finish. */
176 if (errors == 0) {
177 vpiHandle call_handle = vpip_build_vpi_call(argv[0], 0, 0, 0,
178 vpi_argc, vpi_argv);
179 if (call_handle == 0)
180 goto out;
182 vpip_execute_vpi_call(0, call_handle);
183 vpi_free_object(call_handle);
186 out:
187 for (unsigned idx = 0 ; idx < vpi_argc ; idx += 1) {
188 if (vpi_free[idx])
189 vpi_free_object(vpi_free[idx]);
192 free(vpi_argv);
193 free(vpi_free);
196 static void cmd_cont(unsigned, char*[])
198 interact_flag = false;
201 static void cmd_finish(unsigned, char*[])
203 interact_flag = false;
204 schedule_finish(0);
207 static void cmd_help(unsigned, char*[]);
209 static void cmd_list(unsigned, char*[])
211 struct __vpiHandle**table;
212 unsigned ntable;
214 if (stop_current_scope == 0) {
215 vpip_make_root_iterator(table, ntable);
217 } else {
218 table = stop_current_scope->intern;
219 ntable = stop_current_scope->nintern;
222 printf("%u items in this scope:\n", ntable);
223 for (unsigned idx = 0 ; idx < ntable ; idx += 1) {
225 struct __vpiScope*scope;
226 struct __vpiSignal*sig;
228 switch (table[idx]->vpi_type->type_code) {
229 case vpiModule:
230 scope = (struct __vpiScope*) table[idx];
231 printf("module : %s\n", scope->name);
232 break;
234 case vpiTask:
235 scope = (struct __vpiScope*) table[idx];
236 printf("task : %s\n", scope->name);
237 break;
239 case vpiFunction:
240 scope = (struct __vpiScope*) table[idx];
241 printf("function: %s\n", scope->name);
242 break;
244 case vpiNamedBegin:
245 scope = (struct __vpiScope*) table[idx];
246 printf("block : %s\n", scope->name);
247 break;
249 case vpiNamedFork:
250 scope = (struct __vpiScope*) table[idx];
251 printf("fork : %s\n", scope->name);
252 break;
254 case vpiParameter:
255 printf("param : %s\n", vpi_get_str(vpiName, table[idx]));
256 break;
258 case vpiReg:
259 sig = (struct __vpiSignal*) table[idx];
260 if ((sig->msb == 0) && (sig->lsb == 0))
261 printf("reg : %s%s\n", sig->name,
262 sig->signed_flag? "signed " : "");
263 else
264 printf("reg : %s%s[%d:%d]\n", sig->name,
265 sig->signed_flag? "signed " : "",
266 sig->msb, sig->lsb);
267 break;
269 case vpiNet:
270 sig = (struct __vpiSignal*) table[idx];
271 if ((sig->msb == 0) && (sig->lsb == 0))
272 printf("net : %s%s\n", sig->name,
273 sig->signed_flag? "signed " : "");
274 else
275 printf("net : %s%s[%d:%d]\n", sig->name,
276 sig->signed_flag? "signed " : "",
277 sig->msb, sig->lsb);
278 break;
280 default:
281 printf("%8d: <vpi handle>\n",
282 table[idx]->vpi_type->type_code);
283 break;
289 static void cmd_load(unsigned argc, char*argv[])
291 unsigned idx;
293 for (idx = 1 ; idx < argc ; idx += 1) {
294 printf("Loading module %s...\n", argv[idx]);
295 vpip_load_module(argv[idx]);
299 static void cmd_pop(unsigned, char*[])
301 if (stop_current_scope != 0)
302 stop_current_scope = stop_current_scope->scope;
305 static void cmd_push(unsigned argc, char* argv[])
308 for (unsigned idx = 1 ; idx < argc ; idx += 1) {
309 struct __vpiHandle**table;
310 unsigned ntable;
312 struct __vpiScope*child = 0;
314 if (stop_current_scope) {
315 table = stop_current_scope->intern;
316 ntable = stop_current_scope->nintern;
317 } else {
318 vpip_make_root_iterator(table, ntable);
321 child = 0;
322 unsigned tmp;
323 for (tmp = 0 ; tmp < ntable ; tmp += 1) {
324 if (table[tmp]->vpi_type->type_code != vpiModule)
325 continue;
327 struct __vpiScope*cp = (struct __vpiScope*) table[tmp];
329 /* This is a scope, and the name matches, then
330 report that I found the child. */
331 if (strcmp(cp->name, argv[idx]) == 0) {
332 child = cp;
333 break;
337 if (child == 0) {
338 printf("Scope %s not found.\n", argv[idx]);
339 return;
342 stop_current_scope = child;
346 static void cmd_time(unsigned, char*[])
348 unsigned long ticks = schedule_simtime();
349 printf("%lu ticks\n", ticks);
352 static void cmd_where(unsigned, char*[])
354 struct __vpiScope*cur = stop_current_scope;
356 while (cur) {
357 switch (cur->base.vpi_type->type_code) {
358 case vpiModule:
359 printf("module %s\n",
360 cur->name);
361 break;
362 default:
363 printf("scope (%d) %s;\n",
364 cur->base.vpi_type->type_code,
365 cur->name);
366 break;
369 cur = cur->scope;
373 static void cmd_unknown(unsigned, char*argv[])
375 printf("Unknown command: %s\n", argv[0]);
376 printf("Try the help command to get a summary\n"
377 "of available commands.\n");
380 static struct {
381 const char*name;
382 void (*proc)(unsigned argc, char*argv[]);
383 const char*summary;
384 } cmd_table[] = {
385 { "cd", &cmd_push,
386 "Synonym for push."},
387 { "cont", &cmd_cont,
388 "Resume (continue) the simulation"},
389 { "finish", &cmd_finish,
390 "Finish the simulation."},
391 { "help", &cmd_help,
392 "Get help."},
393 { "list", &cmd_list,
394 "List items in the current scope."},
395 { "load", &cmd_load,
396 "Load a VPI module, a la vvp -m."},
397 { "ls", &cmd_list,
398 "Shorthand for \"list\"."},
399 { "pop", &cmd_pop,
400 "Pop one scope from the scope stack."},
401 { "push", &cmd_push,
402 "Descend into the named scope."},
403 { "time", &cmd_time,
404 "Print the current simulation time."},
405 { "where", &cmd_where,
406 "Show current scope, and scope hierarchy stack."},
407 { 0, &cmd_unknown, 0}
410 static void cmd_help(unsigned argc, char*argv[])
412 printf("Commands can be from the following table of base commands,\n"
413 "or can be invocations of system tasks/functions.\n\n");
414 for (unsigned idx = 0 ; cmd_table[idx].name != 0 ; idx += 1) {
415 printf("%-8s - %s\n", cmd_table[idx].name, cmd_table[idx].summary);
418 printf("\nIf the command name starts with a '$' character, it\n"
419 "is taken to be the name of a system task, and a call is\n"
420 "built up and executed.\n");
424 static void invoke_command(char*txt)
426 unsigned argc = 0;
427 char**argv = new char*[strlen(txt)/2];
429 /* Chop the line into words. */
430 for (char*cp = txt+strspn(txt, " ")
431 ; *cp; cp += strspn(cp, " ")) {
432 argv[argc] = cp;
434 if (cp[0] == '"') {
435 char*tmp = strchr(cp+1, '"');
436 if (tmp == 0) {
437 printf("Missing close-quote: %s\n", cp);
438 delete[]argv;
439 return;
442 cp = tmp + 1;
444 } else {
445 cp += strcspn(cp, " ");
448 if (*cp) *cp++ = 0;
450 argc += 1;
454 /* Look up the command, using argv[0] as the key. */
455 if (argc > 0) {
457 if (argv[0][0] == '$') {
458 cmd_call(argc, argv);
460 } else {
461 unsigned idx;
462 for (idx = 0 ; cmd_table[idx].name ; idx += 1)
463 if (strcmp(cmd_table[idx].name, argv[0]) == 0)
464 break;
466 cmd_table[idx].proc (argc, argv);
471 delete[]argv;
474 void stop_handler(int rc)
476 vpi_mcd_printf(1,"** VVP Stop(%d) **\n", rc);
477 vpi_mcd_printf(1,"** Current simulation time is %" TIME_FMT "u ticks.\n",
478 schedule_simtime());
480 interact_flag = true;
481 while (interact_flag) {
482 char*input = readline("> ");
483 if (input == 0)
484 break;
487 /* Advance to the first input character. */
488 char*first = input;
489 while (*first && isspace(*first))
490 first += 1;
492 if (first[0] != 0) {
493 #ifdef HAVE_READLINE_HISTORY_H
494 add_history(first);
495 #endif
496 invoke_command(first);
499 free(input);
502 vpi_mcd_printf(1,"** Continue **\n");
507 * $Log: stop.cc,v $
508 * Revision 1.16 2006/06/18 04:15:50 steve
509 * Add support for system functions in continuous assignments.
511 * Revision 1.15 2005/11/25 18:35:38 steve
512 * stop/continue messages go through MCD for logging.
514 * Revision 1.14 2005/09/20 18:34:02 steve
515 * Clean up compiler warnings.
517 * Revision 1.13 2005/01/29 06:29:17 steve
518 * Support interactive mode even without readline.
520 * Revision 1.12 2004/10/04 01:10:59 steve
521 * Clean up spurious trailing white space.
523 * Revision 1.11 2004/02/21 00:44:34 steve
524 * Add load command to interactive stop.
525 * Support decimal constants passed interactive to system tasks.
527 * Revision 1.10 2003/11/07 05:58:02 steve
528 * Fix conditional compilation of readline history.