Logo Search packages:      
Sourcecode: iverilog version File versions  Download package

stop.cc

/*
 * Copyright (c) 2003-2007 Stephen Williams (steve@icarus.com)
 *
 *    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
 *    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 */

/*
 * 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"

# include  "vpi_priv.h"
# include  "vthread.h"
# include  "schedule.h"
# include  <stdio.h>
# include  <ctype.h>
#ifdef HAVE_READLINE_READLINE_H
# include  <readline/readline.h>
#endif
#ifdef HAVE_READLINE_HISTORY_H
# include  <readline/history.h>
#endif
# include  <string.h>
# include  <stdlib.h>
#ifdef HAVE_MALLOC_H
# include  <malloc.h>
#endif

struct __vpiScope*stop_current_scope = 0;
bool stop_is_finish;  /* When set, $stop acts like $finish (set in main.cc). */

#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


static bool interact_flag = true;

static void cmd_call(unsigned argc, char*argv[])
{
      struct __vpiHandle**table;
      unsigned ntable;

      if (stop_current_scope == 0) {
          vpip_make_root_iterator(table, ntable);

      } else {
          table = stop_current_scope->intern;
          ntable = stop_current_scope->nintern;
      }

      /* This is an array of vpiHandles, for passing to the created
         command. */
      unsigned vpi_argc = argc - 1;
      vpiHandle*vpi_argv = (vpiHandle*)calloc(vpi_argc, sizeof(vpiHandle));
      vpiHandle*vpi_free = (vpiHandle*)calloc(vpi_argc, sizeof(vpiHandle));

      unsigned errors = 0;

      for (unsigned idx = 0 ;  idx < vpi_argc ;  idx += 1) {
          vpiHandle handle = 0;
          bool add_to_free_list = false;

            /* 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))
              handle = &stop_current_scope->base;

            /* Is the argument a quoted string? */
          if (handle == 0 && argv[idx+1][0] == '"') {
              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);
          }

            /* Is the argument a decimal constant? */
          if (handle == 0
            && strspn(argv[idx+1],"0123456789") == strlen(argv[idx+1])) {
              handle = vpip_make_dec_const(strtol(argv[idx+1],0,10));
              add_to_free_list = true;
          }

            /* 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) {
              struct __vpiScope*scope;
              const char*name;

              switch (table[tmp]->vpi_type->type_code) {

                  case vpiModule:
                  case vpiFunction:
                  case vpiTask:
                  case vpiNamedBegin:
                  case vpiNamedFork:
                  scope = (struct __vpiScope*) table[idx];
                  if (strcmp(scope->name, argv[idx+1]) == 0)
                        handle = table[tmp];
                  break;

                  case vpiReg:
                  case vpiNet:
                  case vpiParameter:
                  name = vpi_get_str(vpiName,table[tmp]);
                  if (strcmp(argv[idx+1], name) == 0)
                        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;
          if (add_to_free_list)
              vpi_free[idx] = handle;
          else
              vpi_free[idx] = 0;

      }

      /* 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) {
          vpiHandle call_handle = vpip_build_vpi_call(argv[0], 0, 0, 0,
                                          vpi_argc, vpi_argv,
                                          1, 0);
          if (call_handle == 0)
              goto out;

          vpip_execute_vpi_call(0, call_handle);
          vpi_free_object(call_handle);
      }

 out:
      for (unsigned idx = 0 ;  idx < vpi_argc ;  idx += 1) {
          if (vpi_free[idx])
              vpi_free_object(vpi_free[idx]);
      }

      free(vpi_argv);
      free(vpi_free);
}

static void cmd_cont(unsigned, char*[])
{
      interact_flag = false;
}

static void cmd_finish(unsigned, char*[])
{
      interact_flag = false;
      schedule_finish(0);
}

static void cmd_help(unsigned, char*[]);

static void cmd_list(unsigned, char*[])
{
      struct __vpiHandle**table;
      unsigned ntable;

      if (stop_current_scope == 0) {
          vpip_make_root_iterator(table, ntable);

      } else {
          table = stop_current_scope->intern;
          ntable = stop_current_scope->nintern;
      }

      printf("%u items in this scope:\n", ntable);
      for (unsigned idx = 0 ;  idx < ntable ;  idx += 1) {

          struct __vpiScope*scope;
          struct __vpiSignal*sig;

          switch (table[idx]->vpi_type->type_code) {
            case vpiModule:
              scope = (struct __vpiScope*) table[idx];
              printf("module  : %s\n", scope->name);
              break;

            case vpiTask:
              scope = (struct __vpiScope*) table[idx];
              printf("task    : %s\n", scope->name);
              break;

            case vpiFunction:
              scope = (struct __vpiScope*) table[idx];
              printf("function: %s\n", scope->name);
              break;

            case vpiNamedBegin:
              scope = (struct __vpiScope*) table[idx];
              printf("block   : %s\n", scope->name);
              break;

            case vpiNamedFork:
              scope = (struct __vpiScope*) table[idx];
              printf("fork    : %s\n", scope->name);
              break;

            case vpiParameter:
              printf("param   : %s\n", vpi_get_str(vpiName, table[idx]));
              break;

            case vpiReg:
              sig = (struct __vpiSignal*) table[idx];
              if ((sig->msb == 0) && (sig->lsb == 0))
                  printf("reg     : %s%s\n",
                         vpi_get_str(vpiName, table[idx]),
                         sig->signed_flag? "signed " : "");
              else
                  printf("reg     : %s%s[%d:%d]\n",
                         vpi_get_str(vpiName, table[idx]),
                         sig->signed_flag? "signed " : "",
                         sig->msb, sig->lsb);
              break;

            case vpiNet:
              sig = (struct __vpiSignal*) table[idx];
              if ((sig->msb == 0) && (sig->lsb == 0))
                  printf("net     : %s%s\n",
                         vpi_get_str(vpiName, table[idx]),
                         sig->signed_flag? "signed " : "");
              else
                  printf("net     : %s%s[%d:%d]\n",
                         vpi_get_str(vpiName, table[idx]),
                         sig->signed_flag? "signed " : "",
                         sig->msb, sig->lsb);
              break;

            default:
              printf("%8d: <vpi handle>\n",
                   table[idx]->vpi_type->type_code);
              break;
          }

      }
}

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]);
      }
}

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) {
          struct __vpiHandle**table;
          unsigned ntable;

          struct __vpiScope*child = 0;

          if (stop_current_scope) {
              table = stop_current_scope->intern;
              ntable = stop_current_scope->nintern;
          } else {
              vpip_make_root_iterator(table, ntable);
          }

          child = 0;
          unsigned tmp;
          for (tmp = 0 ;  tmp < ntable ;  tmp += 1) {
              if (table[tmp]->vpi_type->type_code != vpiModule)
                  continue;

              struct __vpiScope*cp = (struct __vpiScope*) table[tmp];

                /* This is a scope, and the name matches, then
                   report that I found the child. */
              if (strcmp(cp->name, argv[idx]) == 0) {
                  child = cp;
                  break;
              }
          }

          if (child == 0) {
              printf("Scope %s not found.\n", argv[idx]);
              return;
          }

          stop_current_scope = child;
      }
}

static void cmd_time(unsigned, char*[])
{
      unsigned long ticks = schedule_simtime();
      printf("%lu ticks\n", ticks);
}

static void cmd_where(unsigned, char*[])
{
      struct __vpiScope*cur = stop_current_scope;

      while (cur) {
          switch (cur->base.vpi_type->type_code) {
            case vpiModule:
              printf("module %s\n",
                   cur->name);
              break;
            default:
              printf("scope (%d) %s;\n",
                   cur->base.vpi_type->type_code,
                   cur->name);
              break;
          }

          cur = cur->scope;
      }
}

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");
}

static struct {
      const char*name;
      void (*proc)(unsigned argc, char*argv[]);
      const char*summary;
} cmd_table[] = {
      { "cd",     &cmd_push,
        "Synonym for push."},
      { "cont",   &cmd_cont,
        "Resume (continue) the simulation"},
      { "finish", &cmd_finish,
        "Finish the simulation."},
      { "help",   &cmd_help,
        "Get help."},
      { "list",   &cmd_list,
        "List items in the current scope."},
      { "load",   &cmd_load,
        "Load a VPI module, a la vvp -m."},
      { "ls",     &cmd_list,
        "Shorthand for \"list\"."},
      { "pop",    &cmd_pop,
        "Pop one scope from the scope stack."},
      { "push",   &cmd_push,
        "Descend into the named scope."},
      { "time",   &cmd_time,
        "Print the current simulation time."},
      { "where",  &cmd_where,
        "Show current scope, and scope hierarchy stack."},
      { 0,        &cmd_unknown, 0}
};

static void cmd_help(unsigned argc, char*argv[])
{
      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);
      }

      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"
           "built up and executed.\n");
}


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, " ")
             ; *cp; cp += strspn(cp, " ")) {
          argv[argc] = cp;

          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;

          argc += 1;
      }


      /* Look up the command, using argv[0] as the key. */
      if (argc > 0) {

          if (argv[0][0] == '$') {
              cmd_call(argc, argv);

          } 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);
          }

      }

      delete[]argv;
}

void stop_handler(int rc)
{
        /* 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) {
          schedule_finish(0);
          return;
      }

      vpi_mcd_printf(1,"** VVP Stop(%d) **\n", rc);
      vpi_mcd_printf(1,"** Current simulation time is %" TIME_FMT_U " ticks.\n",
                 schedule_simtime());

      interact_flag = true;
      while (interact_flag) {
          char*input = readline("> ");
          if (input == 0)
              break;


            /* Advance to the first input character. */
          char*first = input;
          while (*first && isspace(*first))
              first += 1;

          if (first[0] != 0) {
#ifdef HAVE_READLINE_HISTORY_H
              add_history(first);
#endif
              invoke_command(first);
          }

          free(input);
      }

      vpi_mcd_printf(1,"** Continue **\n");
}


Generated by  Doxygen 1.6.0   Back to index