2003-02-21 04:40:35 +01:00
|
|
|
/*
|
2024-06-15 11:47:22 +02:00
|
|
|
* Copyright (c) 2003-2024 Stephen Williams (steve@icarus.com)
|
2003-02-21 04:40:35 +01:00
|
|
|
*
|
|
|
|
|
* This source code is free software; you can redistribute it
|
|
|
|
|
* and/or modify it in source code form under the terms of the GNU
|
|
|
|
|
* General Public License as published by the Free Software
|
|
|
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
|
|
|
* any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
2012-08-29 03:41:23 +02:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2003-02-21 04:40:35 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This file provides a simple command line debugger for the vvp
|
|
|
|
|
* runtime. It is a means to interact with the user running the
|
|
|
|
|
* simulation.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
# include "config.h"
|
|
|
|
|
|
2003-02-22 07:32:36 +01:00
|
|
|
# include "vpi_priv.h"
|
|
|
|
|
# include "vthread.h"
|
2003-02-21 04:40:35 +01:00
|
|
|
# include "schedule.h"
|
2010-05-31 22:12:06 +02:00
|
|
|
# include <cstdio>
|
|
|
|
|
# include <cctype>
|
2009-04-07 19:22:26 +02:00
|
|
|
#ifdef USE_READLINE
|
2003-02-21 04:40:35 +01:00
|
|
|
# include <readline/readline.h>
|
2003-05-16 05:50:28 +02:00
|
|
|
#endif
|
2009-04-07 19:22:26 +02:00
|
|
|
#ifdef USE_HISTORY
|
2003-02-21 04:40:35 +01:00
|
|
|
# include <readline/history.h>
|
|
|
|
|
#endif
|
2010-05-31 22:12:06 +02:00
|
|
|
# include <cstring>
|
|
|
|
|
# include <cstdlib>
|
2010-10-24 00:52:56 +02:00
|
|
|
# include "ivl_alloc.h"
|
2003-02-21 04:40:35 +01:00
|
|
|
|
2015-12-29 22:01:50 +01:00
|
|
|
__vpiScope*stop_current_scope = 0;
|
2024-06-15 11:47:22 +02:00
|
|
|
bool stop_is_finish = false; /* When set, $stop acts like $finish (set in main.cc). */
|
2009-04-24 13:21:58 +02:00
|
|
|
int stop_is_finish_exit_code = 0;
|
2003-02-21 04:40:35 +01:00
|
|
|
|
2005-01-29 07:29:17 +01:00
|
|
|
#ifndef USE_READLINE
|
|
|
|
|
static char* readline_stub(const char*prompt)
|
|
|
|
|
{
|
|
|
|
|
char buf[256];
|
|
|
|
|
|
|
|
|
|
if (prompt && prompt[0]) {
|
|
|
|
|
fputs(prompt, stdout);
|
|
|
|
|
fflush(stdout);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fgets(buf, sizeof(buf), stdin)) {
|
|
|
|
|
char*nl = buf + strlen(buf);
|
|
|
|
|
while (nl > buf && isspace(nl[-1])) {
|
|
|
|
|
nl -= 1;
|
|
|
|
|
nl[0] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return strdup(buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#define readline(x) readline_stub(x)
|
|
|
|
|
#endif
|
|
|
|
|
|
2003-05-16 05:50:28 +02:00
|
|
|
|
2003-02-23 07:41:54 +01:00
|
|
|
static bool interact_flag = true;
|
2003-02-21 04:40:35 +01:00
|
|
|
|
2003-02-22 07:32:36 +01:00
|
|
|
static void cmd_call(unsigned argc, char*argv[])
|
|
|
|
|
{
|
2012-02-12 22:21:30 +01:00
|
|
|
__vpiHandle**table;
|
2003-02-23 07:41:54 +01:00
|
|
|
unsigned ntable;
|
|
|
|
|
|
|
|
|
|
if (stop_current_scope == 0) {
|
|
|
|
|
vpip_make_root_iterator(table, ntable);
|
|
|
|
|
|
|
|
|
|
} else {
|
2015-12-24 02:38:13 +01:00
|
|
|
table = &stop_current_scope->intern[0];
|
|
|
|
|
ntable = stop_current_scope->intern.size();
|
2003-02-23 07:41:54 +01:00
|
|
|
}
|
|
|
|
|
|
2003-02-24 07:35:45 +01:00
|
|
|
/* This is an array of vpiHandles, for passing to the created
|
|
|
|
|
command. */
|
2003-02-23 07:41:54 +01:00
|
|
|
unsigned vpi_argc = argc - 1;
|
|
|
|
|
vpiHandle*vpi_argv = (vpiHandle*)calloc(vpi_argc, sizeof(vpiHandle));
|
2003-02-24 07:35:45 +01:00
|
|
|
vpiHandle*vpi_free = (vpiHandle*)calloc(vpi_argc, sizeof(vpiHandle));
|
2003-02-23 07:41:54 +01:00
|
|
|
|
|
|
|
|
unsigned errors = 0;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < vpi_argc ; idx += 1) {
|
|
|
|
|
vpiHandle handle = 0;
|
2003-02-24 07:35:45 +01:00
|
|
|
bool add_to_free_list = false;
|
2003-02-23 07:41:54 +01:00
|
|
|
|
|
|
|
|
/* Detect the special case that the argument is the
|
|
|
|
|
.(dot) string. This represents the handle for the
|
|
|
|
|
current scope. */
|
|
|
|
|
if (stop_current_scope && (strcmp(argv[idx+1], ".") == 0))
|
2012-01-19 19:16:39 +01:00
|
|
|
handle = stop_current_scope;
|
2003-02-23 07:41:54 +01:00
|
|
|
|
2004-02-21 01:44:34 +01:00
|
|
|
/* Is the argument a quoted string? */
|
|
|
|
|
if (handle == 0 && argv[idx+1][0] == '"') {
|
2003-02-24 07:35:45 +01:00
|
|
|
char*tmp = strdup(argv[idx+1]);
|
|
|
|
|
tmp[strlen(tmp)-1] = 0;
|
|
|
|
|
|
|
|
|
|
/* Create a temporary vpiStringConst to pass as a
|
|
|
|
|
handle. Make it temporary so that memory is
|
|
|
|
|
reclaimed after the call is completed. */
|
|
|
|
|
handle = vpip_make_string_const(strdup(tmp+1), false);
|
|
|
|
|
add_to_free_list = true;
|
|
|
|
|
free(tmp);
|
|
|
|
|
}
|
|
|
|
|
|
2004-02-21 01:44:34 +01:00
|
|
|
/* Is the argument a decimal constant? */
|
|
|
|
|
if (handle == 0
|
|
|
|
|
&& strspn(argv[idx+1],"0123456789") == strlen(argv[idx+1])) {
|
2012-01-19 19:16:39 +01:00
|
|
|
handle = new __vpiDecConst(strtol(argv[idx+1],0,10));
|
2004-02-21 01:44:34 +01:00
|
|
|
add_to_free_list = true;
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-23 07:41:54 +01:00
|
|
|
/* Try to find the vpiHandle within this scope that has
|
|
|
|
|
the name in argv[idx+2]. Look in the current scope. */
|
|
|
|
|
|
|
|
|
|
for (unsigned tmp = 0 ; (tmp < ntable)&& !handle ; tmp += 1) {
|
2015-12-29 22:01:50 +01:00
|
|
|
__vpiScope*scope;
|
2003-03-11 00:37:07 +01:00
|
|
|
const char*name;
|
2003-02-23 07:41:54 +01:00
|
|
|
|
2012-01-19 19:16:39 +01:00
|
|
|
switch (table[tmp]->get_type_code()) {
|
2003-02-23 07:41:54 +01:00
|
|
|
|
|
|
|
|
case vpiModule:
|
2013-07-17 19:55:46 +02:00
|
|
|
case vpiGenScope:
|
2003-02-23 07:41:54 +01:00
|
|
|
case vpiFunction:
|
|
|
|
|
case vpiTask:
|
|
|
|
|
case vpiNamedBegin:
|
|
|
|
|
case vpiNamedFork:
|
2023-08-17 07:44:31 +02:00
|
|
|
scope = dynamic_cast<__vpiScope*>(table[tmp]);
|
2015-12-21 05:26:57 +01:00
|
|
|
if (strcmp(scope->scope_name(), argv[idx+1]) == 0)
|
2003-02-23 07:41:54 +01:00
|
|
|
handle = table[tmp];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case vpiReg:
|
|
|
|
|
case vpiNet:
|
2003-03-11 00:37:07 +01:00
|
|
|
case vpiParameter:
|
|
|
|
|
name = vpi_get_str(vpiName,table[tmp]);
|
|
|
|
|
if (strcmp(argv[idx+1], name) == 0)
|
2003-02-23 07:41:54 +01:00
|
|
|
handle = table[tmp];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (handle == 0) {
|
|
|
|
|
printf("call error: I don't know how to"
|
|
|
|
|
" pass %s to %s\n", argv[idx+1], argv[0]);
|
|
|
|
|
errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vpi_argv[idx] = handle;
|
2003-02-24 07:35:45 +01:00
|
|
|
if (add_to_free_list)
|
|
|
|
|
vpi_free[idx] = handle;
|
|
|
|
|
else
|
|
|
|
|
vpi_free[idx] = 0;
|
|
|
|
|
|
2003-02-23 07:41:54 +01:00
|
|
|
}
|
2003-02-22 07:32:36 +01:00
|
|
|
|
2003-02-23 07:41:54 +01:00
|
|
|
/* If there are no errors so far, then make up a call to the
|
|
|
|
|
vpi task and execute that call. Free the call structure
|
|
|
|
|
when we finish. */
|
|
|
|
|
if (errors == 0) {
|
2006-06-18 06:15:50 +02:00
|
|
|
vpiHandle call_handle = vpip_build_vpi_call(argv[0], 0, 0, 0,
|
2010-06-09 20:56:00 +02:00
|
|
|
true, false,
|
|
|
|
|
vpi_argc, vpi_argv,
|
2014-01-04 23:06:58 +01:00
|
|
|
0, 0, 0,
|
2010-06-09 20:56:00 +02:00
|
|
|
1, 0);
|
2003-02-24 07:35:45 +01:00
|
|
|
if (call_handle == 0)
|
|
|
|
|
goto out;
|
2003-02-22 07:32:36 +01:00
|
|
|
|
2003-02-23 07:41:54 +01:00
|
|
|
vpip_execute_vpi_call(0, call_handle);
|
|
|
|
|
vpi_free_object(call_handle);
|
|
|
|
|
}
|
2003-02-22 07:32:36 +01:00
|
|
|
|
2003-02-24 07:35:45 +01:00
|
|
|
out:
|
|
|
|
|
for (unsigned idx = 0 ; idx < vpi_argc ; idx += 1) {
|
|
|
|
|
if (vpi_free[idx])
|
|
|
|
|
vpi_free_object(vpi_free[idx]);
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-23 07:41:54 +01:00
|
|
|
free(vpi_argv);
|
2003-02-24 07:35:45 +01:00
|
|
|
free(vpi_free);
|
2003-02-22 07:32:36 +01:00
|
|
|
}
|
|
|
|
|
|
2003-02-21 04:40:35 +01:00
|
|
|
static void cmd_cont(unsigned, char*[])
|
|
|
|
|
{
|
|
|
|
|
interact_flag = false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-07 01:08:20 +01:00
|
|
|
static void cmd_step(unsigned, char*[])
|
|
|
|
|
{
|
|
|
|
|
interact_flag = false;
|
|
|
|
|
schedule_single_step(0);
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-21 04:40:35 +01:00
|
|
|
static void cmd_finish(unsigned, char*[])
|
|
|
|
|
{
|
|
|
|
|
interact_flag = false;
|
|
|
|
|
schedule_finish(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void cmd_help(unsigned, char*[]);
|
|
|
|
|
|
2003-02-23 07:41:54 +01:00
|
|
|
static void cmd_list(unsigned, char*[])
|
|
|
|
|
{
|
2012-02-12 22:21:30 +01:00
|
|
|
__vpiHandle**table;
|
2003-02-23 07:41:54 +01:00
|
|
|
unsigned ntable;
|
|
|
|
|
|
|
|
|
|
if (stop_current_scope == 0) {
|
|
|
|
|
vpip_make_root_iterator(table, ntable);
|
|
|
|
|
|
|
|
|
|
} else {
|
2015-12-24 02:38:13 +01:00
|
|
|
table = &stop_current_scope->intern[0];
|
|
|
|
|
ntable = stop_current_scope->intern.size();
|
2003-02-23 07:41:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf("%u items in this scope:\n", ntable);
|
|
|
|
|
for (unsigned idx = 0 ; idx < ntable ; idx += 1) {
|
|
|
|
|
|
2015-12-29 22:01:50 +01:00
|
|
|
__vpiScope*scope;
|
2003-02-23 07:41:54 +01:00
|
|
|
struct __vpiSignal*sig;
|
|
|
|
|
|
2012-01-19 19:16:39 +01:00
|
|
|
switch (table[idx]->get_type_code()) {
|
2022-02-26 20:12:50 +01:00
|
|
|
case vpiPackage:
|
|
|
|
|
scope = dynamic_cast<__vpiScope*>(table[idx]);
|
|
|
|
|
printf("package : %s\n", scope->scope_name());
|
|
|
|
|
break;
|
|
|
|
|
|
2003-02-23 07:41:54 +01:00
|
|
|
case vpiModule:
|
2012-01-19 19:16:39 +01:00
|
|
|
scope = dynamic_cast<__vpiScope*>(table[idx]);
|
2015-12-21 05:26:57 +01:00
|
|
|
printf("module : %s\n", scope->scope_name());
|
2013-07-17 19:55:46 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case vpiGenScope:
|
|
|
|
|
scope = dynamic_cast<__vpiScope*>(table[idx]);
|
2015-12-21 05:26:57 +01:00
|
|
|
printf("generate: %s\n", scope->scope_name());
|
2003-02-23 07:41:54 +01:00
|
|
|
break;
|
|
|
|
|
|
2004-02-21 01:44:34 +01:00
|
|
|
case vpiTask:
|
2012-01-19 19:16:39 +01:00
|
|
|
scope = dynamic_cast<__vpiScope*>(table[idx]);
|
2015-12-21 05:26:57 +01:00
|
|
|
printf("task : %s\n", scope->scope_name());
|
2004-02-21 01:44:34 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case vpiFunction:
|
2012-01-19 19:16:39 +01:00
|
|
|
scope = dynamic_cast<__vpiScope*>(table[idx]);
|
2015-12-21 05:26:57 +01:00
|
|
|
printf("function: %s\n", scope->scope_name());
|
2004-02-21 01:44:34 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case vpiNamedBegin:
|
2012-01-19 19:16:39 +01:00
|
|
|
scope = dynamic_cast<__vpiScope*>(table[idx]);
|
2015-12-21 05:26:57 +01:00
|
|
|
printf("block : %s\n", scope->scope_name());
|
2004-02-21 01:44:34 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case vpiNamedFork:
|
2012-01-19 19:16:39 +01:00
|
|
|
scope = dynamic_cast<__vpiScope*>(table[idx]);
|
2015-12-21 05:26:57 +01:00
|
|
|
printf("fork : %s\n", scope->scope_name());
|
2004-02-21 01:44:34 +01:00
|
|
|
break;
|
|
|
|
|
|
2003-03-11 00:37:07 +01:00
|
|
|
case vpiParameter:
|
|
|
|
|
printf("param : %s\n", vpi_get_str(vpiName, table[idx]));
|
|
|
|
|
break;
|
|
|
|
|
|
2003-02-23 07:41:54 +01:00
|
|
|
case vpiReg:
|
2012-01-19 19:16:39 +01:00
|
|
|
sig = dynamic_cast<__vpiSignal*>(table[idx]);
|
2014-06-20 00:39:24 +02:00
|
|
|
if ((sig->msb.get_value() == 0) && (sig->lsb.get_value() == 0))
|
2007-12-03 20:41:52 +01:00
|
|
|
printf("reg : %s%s\n",
|
|
|
|
|
vpi_get_str(vpiName, table[idx]),
|
2003-02-23 07:41:54 +01:00
|
|
|
sig->signed_flag? "signed " : "");
|
|
|
|
|
else
|
2007-12-03 20:41:52 +01:00
|
|
|
printf("reg : %s%s[%d:%d]\n",
|
|
|
|
|
vpi_get_str(vpiName, table[idx]),
|
2003-02-23 07:41:54 +01:00
|
|
|
sig->signed_flag? "signed " : "",
|
2014-06-20 00:39:24 +02:00
|
|
|
sig->msb.get_value(), sig->lsb.get_value());
|
2003-02-23 07:41:54 +01:00
|
|
|
break;
|
|
|
|
|
|
2003-10-15 04:17:39 +02:00
|
|
|
case vpiNet:
|
2012-01-19 19:16:39 +01:00
|
|
|
sig = dynamic_cast<__vpiSignal*>(table[idx]);
|
2014-06-20 00:39:24 +02:00
|
|
|
if ((sig->msb.get_value() == 0) && (sig->lsb.get_value() == 0))
|
2007-12-03 20:41:52 +01:00
|
|
|
printf("net : %s%s\n",
|
|
|
|
|
vpi_get_str(vpiName, table[idx]),
|
2003-10-15 04:17:39 +02:00
|
|
|
sig->signed_flag? "signed " : "");
|
|
|
|
|
else
|
2007-12-03 20:41:52 +01:00
|
|
|
printf("net : %s%s[%d:%d]\n",
|
|
|
|
|
vpi_get_str(vpiName, table[idx]),
|
2003-10-15 04:17:39 +02:00
|
|
|
sig->signed_flag? "signed " : "",
|
2014-06-20 00:39:24 +02:00
|
|
|
sig->msb.get_value(), sig->lsb.get_value());
|
2003-10-15 04:17:39 +02:00
|
|
|
break;
|
|
|
|
|
|
2022-02-26 20:12:50 +01:00
|
|
|
case vpiPort:
|
|
|
|
|
printf("port : %s -- %s\n",
|
|
|
|
|
vpi_get_str(vpiName, table[idx]),
|
|
|
|
|
direction_as_string(vpi_get(vpiDirection, table[idx])));
|
|
|
|
|
break;
|
|
|
|
|
|
2003-02-23 07:41:54 +01:00
|
|
|
default:
|
2022-02-26 20:12:50 +01:00
|
|
|
printf("%8s: <vpi handle>\n",
|
|
|
|
|
vpi_type_as_string(table[idx]->get_type_code()));
|
2003-02-23 07:41:54 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-02-21 01:44:34 +01:00
|
|
|
static void cmd_load(unsigned argc, char*argv[])
|
|
|
|
|
{
|
|
|
|
|
unsigned idx;
|
|
|
|
|
|
|
|
|
|
for (idx = 1 ; idx < argc ; idx += 1) {
|
|
|
|
|
printf("Loading module %s...\n", argv[idx]);
|
|
|
|
|
vpip_load_module(argv[idx]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-23 07:41:54 +01:00
|
|
|
static void cmd_pop(unsigned, char*[])
|
|
|
|
|
{
|
|
|
|
|
if (stop_current_scope != 0)
|
|
|
|
|
stop_current_scope = stop_current_scope->scope;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void cmd_push(unsigned argc, char* argv[])
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 1 ; idx < argc ; idx += 1) {
|
2012-02-12 22:21:30 +01:00
|
|
|
__vpiHandle**table;
|
2003-02-23 07:41:54 +01:00
|
|
|
unsigned ntable;
|
|
|
|
|
|
|
|
|
|
if (stop_current_scope) {
|
2015-12-24 02:38:13 +01:00
|
|
|
table = &stop_current_scope->intern[0];
|
|
|
|
|
ntable = stop_current_scope->intern.size();
|
2003-02-23 07:41:54 +01:00
|
|
|
} else {
|
|
|
|
|
vpip_make_root_iterator(table, ntable);
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-26 20:12:50 +01:00
|
|
|
__vpiScope*child = 0;
|
|
|
|
|
for (unsigned tmp = 0 ; tmp < ntable ; tmp += 1) {
|
|
|
|
|
// Try to convert this item to a scope. If this is not a
|
|
|
|
|
// scope, then continue.
|
|
|
|
|
__vpiScope*scope = dynamic_cast<__vpiScope*>(table[tmp]);
|
|
|
|
|
if (scope == 0)
|
2003-02-23 07:41:54 +01:00
|
|
|
continue;
|
|
|
|
|
|
2022-02-26 20:12:50 +01:00
|
|
|
// This is a scope, and the name matches, then
|
|
|
|
|
// report that I found the child.
|
|
|
|
|
if (strcmp(scope->scope_name(), argv[idx]) == 0) {
|
|
|
|
|
child = scope;
|
2003-02-23 07:41:54 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (child == 0) {
|
|
|
|
|
printf("Scope %s not found.\n", argv[idx]);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stop_current_scope = child;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-21 04:40:35 +01:00
|
|
|
static void cmd_time(unsigned, char*[])
|
|
|
|
|
{
|
|
|
|
|
unsigned long ticks = schedule_simtime();
|
|
|
|
|
printf("%lu ticks\n", ticks);
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-04 03:54:46 +01:00
|
|
|
static void cmd_trace(unsigned argc, char*argv[])
|
|
|
|
|
{
|
|
|
|
|
assert(argc);
|
|
|
|
|
switch (argc) {
|
|
|
|
|
case 1:
|
|
|
|
|
show_file_line = true;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
printf("Only using the first argument to trace.\n");
|
2018-10-06 21:13:31 +02:00
|
|
|
// fallthrough
|
2011-03-04 03:54:46 +01:00
|
|
|
case 2:
|
|
|
|
|
if ((strcmp(argv[1], "on") == 0) || (strcmp(argv[1], "1") == 0)) {
|
|
|
|
|
show_file_line = true;
|
|
|
|
|
} else show_file_line = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* You can't trace a file if the compiler didn't insert the
|
|
|
|
|
* %file_line opcodes. */
|
|
|
|
|
if (!code_is_instrumented) {
|
|
|
|
|
printf("The vvp input must be instrumented before tracing is "
|
|
|
|
|
"available.\n");
|
|
|
|
|
printf("Recompile with the -pfileline=1 flag to instrument "
|
|
|
|
|
"the input.\n");
|
|
|
|
|
show_file_line = false;
|
|
|
|
|
} else {
|
|
|
|
|
printf("Turning statement tracing %s.\n",
|
|
|
|
|
show_file_line ? "on" : "off");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-23 07:41:54 +01:00
|
|
|
static void cmd_where(unsigned, char*[])
|
|
|
|
|
{
|
2015-12-29 22:01:50 +01:00
|
|
|
__vpiScope*cur = stop_current_scope;
|
2003-02-23 07:41:54 +01:00
|
|
|
|
|
|
|
|
while (cur) {
|
2012-01-19 19:16:39 +01:00
|
|
|
switch (cur->get_type_code()) {
|
2003-02-23 07:41:54 +01:00
|
|
|
case vpiModule:
|
2015-12-21 05:26:57 +01:00
|
|
|
printf("module %s\n", cur->scope_name());
|
2003-02-23 07:41:54 +01:00
|
|
|
break;
|
2022-02-26 20:12:50 +01:00
|
|
|
case vpiGenScope:
|
|
|
|
|
printf("generate %s\n", cur->scope_name());
|
|
|
|
|
break;
|
2003-02-23 07:41:54 +01:00
|
|
|
default:
|
2015-12-21 05:26:57 +01:00
|
|
|
printf("scope (%d) %s;\n", cur->get_type_code(), cur->scope_name());
|
2003-02-23 07:41:54 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cur = cur->scope;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-21 04:40:35 +01:00
|
|
|
static void cmd_unknown(unsigned, char*argv[])
|
|
|
|
|
{
|
|
|
|
|
printf("Unknown command: %s\n", argv[0]);
|
|
|
|
|
printf("Try the help command to get a summary\n"
|
|
|
|
|
"of available commands.\n");
|
|
|
|
|
}
|
|
|
|
|
|
2005-09-20 20:34:01 +02:00
|
|
|
static struct {
|
2004-10-04 03:10:51 +02:00
|
|
|
const char*name;
|
2003-02-21 04:40:35 +01:00
|
|
|
void (*proc)(unsigned argc, char*argv[]);
|
|
|
|
|
const char*summary;
|
|
|
|
|
} cmd_table[] = {
|
2003-02-23 07:41:54 +01:00
|
|
|
{ "cd", &cmd_push,
|
|
|
|
|
"Synonym for push."},
|
2003-02-21 04:40:35 +01:00
|
|
|
{ "cont", &cmd_cont,
|
|
|
|
|
"Resume (continue) the simulation"},
|
2024-06-17 19:18:52 +02:00
|
|
|
{ "exit", &cmd_finish,
|
|
|
|
|
"Synonym for finish."},
|
2003-02-21 04:40:35 +01:00
|
|
|
{ "finish", &cmd_finish,
|
|
|
|
|
"Finish the simulation."},
|
2003-02-23 07:41:54 +01:00
|
|
|
{ "help", &cmd_help,
|
2003-02-21 04:40:35 +01:00
|
|
|
"Get help."},
|
2003-02-23 07:41:54 +01:00
|
|
|
{ "list", &cmd_list,
|
|
|
|
|
"List items in the current scope."},
|
2004-02-21 01:44:34 +01:00
|
|
|
{ "load", &cmd_load,
|
|
|
|
|
"Load a VPI module, a la vvp -m."},
|
|
|
|
|
{ "ls", &cmd_list,
|
|
|
|
|
"Shorthand for \"list\"."},
|
2003-02-23 07:41:54 +01:00
|
|
|
{ "pop", &cmd_pop,
|
|
|
|
|
"Pop one scope from the scope stack."},
|
|
|
|
|
{ "push", &cmd_push,
|
|
|
|
|
"Descend into the named scope."},
|
2010-01-07 01:08:20 +01:00
|
|
|
{ "step", &cmd_step,
|
|
|
|
|
"Single-step the scheduler for 1 event."},
|
2003-02-21 04:40:35 +01:00
|
|
|
{ "time", &cmd_time,
|
|
|
|
|
"Print the current simulation time."},
|
2011-03-04 03:54:46 +01:00
|
|
|
{ "trace", &cmd_trace,
|
|
|
|
|
"Control statement tracing (on/off) when the code is instrumented."},
|
2003-02-23 07:41:54 +01:00
|
|
|
{ "where", &cmd_where,
|
|
|
|
|
"Show current scope, and scope hierarchy stack."},
|
2003-02-21 04:40:35 +01:00
|
|
|
{ 0, &cmd_unknown, 0}
|
|
|
|
|
};
|
|
|
|
|
|
2010-10-11 06:52:26 +02:00
|
|
|
static void cmd_help(unsigned, char*[])
|
2003-02-21 04:40:35 +01:00
|
|
|
{
|
|
|
|
|
printf("Commands can be from the following table of base commands,\n"
|
|
|
|
|
"or can be invocations of system tasks/functions.\n\n");
|
|
|
|
|
for (unsigned idx = 0 ; cmd_table[idx].name != 0 ; idx += 1) {
|
|
|
|
|
printf("%-8s - %s\n", cmd_table[idx].name, cmd_table[idx].summary);
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-23 07:41:54 +01:00
|
|
|
printf("\nIf the command name starts with a '$' character, it\n"
|
|
|
|
|
"is taken to be the name of a system task, and a call is\n"
|
2022-02-26 20:12:50 +01:00
|
|
|
"built up and executed. For example, \"$display foo\" will\n"
|
|
|
|
|
"call the function as $display(foo).\n");
|
2003-02-21 04:40:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void invoke_command(char*txt)
|
|
|
|
|
{
|
|
|
|
|
unsigned argc = 0;
|
|
|
|
|
char**argv = new char*[strlen(txt)/2];
|
|
|
|
|
|
|
|
|
|
/* Chop the line into words. */
|
|
|
|
|
for (char*cp = txt+strspn(txt, " ")
|
2004-10-04 03:10:51 +02:00
|
|
|
; *cp; cp += strspn(cp, " ")) {
|
2003-02-21 04:40:35 +01:00
|
|
|
argv[argc] = cp;
|
|
|
|
|
|
2003-02-24 07:35:45 +01:00
|
|
|
if (cp[0] == '"') {
|
|
|
|
|
char*tmp = strchr(cp+1, '"');
|
|
|
|
|
if (tmp == 0) {
|
|
|
|
|
printf("Missing close-quote: %s\n", cp);
|
|
|
|
|
delete[]argv;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cp = tmp + 1;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
cp += strcspn(cp, " ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (*cp) *cp++ = 0;
|
2003-02-21 04:40:35 +01:00
|
|
|
|
|
|
|
|
argc += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-23 07:41:54 +01:00
|
|
|
|
2003-02-21 04:40:35 +01:00
|
|
|
/* Look up the command, using argv[0] as the key. */
|
|
|
|
|
if (argc > 0) {
|
|
|
|
|
|
2003-02-23 07:41:54 +01:00
|
|
|
if (argv[0][0] == '$') {
|
2009-04-11 00:36:07 +02:00
|
|
|
if (strcmp(argv[0], "$stop") == 0) {
|
|
|
|
|
printf("The simulator is already stopped!\n");
|
|
|
|
|
} else if (strcmp(argv[0], "$finish") == 0){
|
|
|
|
|
cmd_finish(argc, argv);
|
|
|
|
|
} else {
|
|
|
|
|
cmd_call(argc, argv);
|
|
|
|
|
}
|
2003-02-23 07:41:54 +01:00
|
|
|
} else {
|
|
|
|
|
unsigned idx;
|
|
|
|
|
for (idx = 0 ; cmd_table[idx].name ; idx += 1)
|
|
|
|
|
if (strcmp(cmd_table[idx].name, argv[0]) == 0)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
cmd_table[idx].proc (argc, argv);
|
|
|
|
|
}
|
2003-02-21 04:40:35 +01:00
|
|
|
|
2003-02-24 07:35:45 +01:00
|
|
|
}
|
2003-02-21 04:40:35 +01:00
|
|
|
|
|
|
|
|
delete[]argv;
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-20 01:41:22 +02:00
|
|
|
static void invoke_command_const(const char*txt)
|
|
|
|
|
{
|
|
|
|
|
char *vtxt = strdup(txt);
|
|
|
|
|
invoke_command(vtxt);
|
|
|
|
|
free(vtxt);
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-21 04:40:35 +01:00
|
|
|
void stop_handler(int rc)
|
|
|
|
|
{
|
2007-12-30 07:26:02 +01:00
|
|
|
/* The user may be running in a non-interactive environment, so
|
|
|
|
|
* they want $stop and <Control-C> to be the same as $finish. */
|
|
|
|
|
if (stop_is_finish) {
|
2019-10-14 23:11:50 +02:00
|
|
|
vpip_set_return_value(stop_is_finish_exit_code);
|
2007-12-30 07:26:02 +01:00
|
|
|
schedule_finish(0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-25 19:35:38 +01:00
|
|
|
vpi_mcd_printf(1,"** VVP Stop(%d) **\n", rc);
|
2009-04-16 23:24:58 +02:00
|
|
|
vpi_mcd_printf(1,"** Flushing output streams.\n");
|
2009-05-20 01:41:22 +02:00
|
|
|
invoke_command_const("$fflush");
|
|
|
|
|
invoke_command_const("$dumpflush");
|
2009-03-20 21:21:12 +01:00
|
|
|
vpi_mcd_printf(1,"** Current simulation time is %" TIME_FMT_U " ticks.\n",
|
2005-11-25 19:35:38 +01:00
|
|
|
schedule_simtime());
|
2003-02-21 04:40:35 +01:00
|
|
|
|
|
|
|
|
interact_flag = true;
|
|
|
|
|
while (interact_flag) {
|
|
|
|
|
char*input = readline("> ");
|
|
|
|
|
if (input == 0)
|
|
|
|
|
break;
|
|
|
|
|
|
2003-02-24 07:35:45 +01:00
|
|
|
|
2003-02-21 04:40:35 +01:00
|
|
|
/* Advance to the first input character. */
|
|
|
|
|
char*first = input;
|
|
|
|
|
while (*first && isspace(*first))
|
|
|
|
|
first += 1;
|
|
|
|
|
|
2003-02-24 07:35:45 +01:00
|
|
|
if (first[0] != 0) {
|
2009-04-07 19:22:26 +02:00
|
|
|
#ifdef USE_HISTORY
|
2003-02-24 07:35:45 +01:00
|
|
|
add_history(first);
|
2003-05-16 05:50:28 +02:00
|
|
|
#endif
|
2003-02-24 07:35:45 +01:00
|
|
|
invoke_command(first);
|
|
|
|
|
}
|
2003-02-21 04:40:35 +01:00
|
|
|
|
|
|
|
|
free(input);
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-25 19:35:38 +01:00
|
|
|
vpi_mcd_printf(1,"** Continue **\n");
|
2003-02-21 04:40:35 +01:00
|
|
|
}
|