Subversion Repositories Open64

[/] [sim/] [fsim/] [shell/] [tclapi.cpp] - Rev 2072

Compare with Previous | Blame | View Log

/*
 *  File: tclapi.cpp
 * 
 *  Copyright (c) 2006 Beijing SimpLight Nanoelectornics, Ltd.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without modification, 
 *  are permitted provided that the following conditions are met:
 *
 *  1.Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimer. 
 *  2.Redistributions in binary form must reproduce the above copyright notice, 
 *    this list of conditions and the following disclaimer in the documentation 
 *    and/or other materials provided with the distribution. 
 *
 *  THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY EXPRESS 
 *  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
 *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 *  IN NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 *  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
 *  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
 *  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
 *  OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * 
 * To add a command, you must do as following:
 *   1. Add command usage in shellbase.cpp. For complex command, you must add a 
 *      detailed usage guide too.
 *   2. Add a command proc here.
 *   3. Register that command in Tcl_AppInit.
 */
#include "defs.h"
#include "symtable.h"
#include "tclapi.h"
#include "shellbase.h"
#include "tclInt.h"
#include <signal.h>
#include "longjmp.h"
#include <string>

using std::string;

#define SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER "Error: Wrong # of arguments"


#define VAR_ACTIVE_THREAD_NAME "thread"
#define VAR_VERBOSE_NAME "verbose"
#define VAR_MULTI_THREAD_NAME "mt"
#define VAR_BB_THREAD_NAME "BB"
#define VAR_CORE_THREAD_NAME "Core"
#define OS_THREAD_ID_SYMBOL "os_task_id_sym"

#define VAR_SL2_TH0_THREAD_NAME "TH0"
#define VAR_SL2_TH1_THREAD_NAME "TH1"
#define VAR_SL2_TH2_THREAD_NAME "TH2"
#define VAR_SL2_TH3_THREAD_NAME "TH3"
#define VAR_SL2_TH4_THREAD_NAME "TH4"

ShellBase * tcl_shell_ptr;

Tcl_Interp *gInterp;

char *ActiveThreadName = NULL;
INT MultiThreadingMode = EXEC_SINGLE;// parallel mode

// static variables for print and x command
#define MAX_DUMP_CMD 256
static char _last_dump_cmd[256];
static ADDR _last_mem_dump_addr=0;  // used by print and x command
static bool _is_expr = false; // indicates if the _last_dump_cmd contains a command or an expression 
static char _last_fmt_char='\0';  // format specification will be used by print and x command for repeating.
static int _last_unit_size = 4;
static int _last_repeat_count = 1; // used by print and x command

ShellBase* getActiveShell() { return tcl_shell_ptr; }

bool    fsim_is_reg_readonly(const char *name) { 
  if (strcmp(name, "zero") == 0)
    return true;
  else if (strcmp(name, "r0") == 0)
    return true;
  return false;
}

int fsim_link_short(char *name, short *varAddr, int mode)
{
  if (mode == 0)
    mode = TCL_LINK_READ_ONLY;
  else
    mode = 0;
    
  SimFatal(gInterp, ("Invalid TCL shell"));
  Tcl_UnlinkVar(gInterp, name);
//  printf("link %s at 0x%x\n", name, varAddr);
  return Tcl_LinkVar(gInterp, name, (char*)varAddr, TCL_LINK_SHORT | mode);
}

int fsim_link_int(char *name, int *varAddr, int mode)
{
  if (mode == 0)
    mode = TCL_LINK_READ_ONLY;
  else
    mode = 0;
    
  SimFatal(gInterp, ("Invalid TCL shell"));
  Tcl_UnlinkVar(gInterp, name);
//  printf("link %s at 0x%x\n", name, varAddr);
  return Tcl_LinkVar(gInterp, name, (char*)varAddr, TCL_LINK_INT | mode);
}

int fsim_link_dword(char *name, DWORD *varAddr)
{
  SimFatal(gInterp, ("Invalid TCL shell"));
  Tcl_UnlinkVar(gInterp, name);
//  printf("linkd %s at 0x%x\n", name, varAddr);
  return Tcl_LinkVar(gInterp, name, (char*)varAddr, TCL_LINK_WIDE_INT);
}

int fsim_link_str(char *name, const char *varAddr, int mode)
{
  if (mode == 0)
    mode = TCL_LINK_READ_ONLY;
  else
    mode = 0;
    
  SimFatal(gInterp, ("Invalid TCL shell"));
  Tcl_UnlinkVar(gInterp, name);
//  printf("link %s at 0x%x\n", name, varAddr);
  return Tcl_LinkVar(gInterp, name, (char*)varAddr, TCL_LINK_STRING | mode);
}

int fsim_set_prompt(void) {
  Tcl_SetVar(gInterp, "sl_prompt", getActiveShell()->cmdGetPrompt(), TCL_GLOBAL_ONLY);
  return TCL_OK;
}

static Tcl_Interp *tcl_interp_copy = NULL;

/*
 * mode: 0, dont disassemble after execution; assemble current instruction after execution;
 */
int ExecSteps(ADDR addr, int steps, int mode)
{
  // Use machine class
  if (addr == ADDR_NOT_SPECIFIED)
    addr = getActiveShell()->cmdGetPC();
  if (!getActiveShell()->cmdGetElf()) {
    // No elf object loaded. Run from memory.
    getActiveShell()->cmdRunMem(addr, steps, mode);
  } else {
    if (mode) {
      getActiveShell()->cmdStepElf((UINT)steps, true,MultiThreadingMode);
    } else {
      getActiveShell()->cmdStepElf((UINT)steps, false,MultiThreadingMode);
    }
  }
  return TCL_OK;
}

int GetAddrFromString(Tcl_Interp *interp, ADDR &addr, const char *symOrAddr) {
  addr = (ADDR)-1;
  // try to get a symbol address
  if ((addr = getActiveShell()->cmdGetSymbolAddr(symOrAddr)) == SYM_UNDEF) {
    if (Tcl_ExprLong(interp, symOrAddr, (long*)&addr) != TCL_OK ) {
      fprintf(stderr, "Invalid symbol or address:%s", symOrAddr);
      return TCL_ERROR;
    }
  }
  return TCL_OK;
}

int GetSymbolValue(Tcl_Interp *interp, ADDR &addr, const char *sym) {
  addr = (ADDR)-1;
  // try to get a symbol address
  if ((addr = getActiveShell()->cmdGetSymbolAddr(sym)) == SYM_UNDEF) {
    return TCL_ERROR;
  }
  return TCL_OK;
}

//Do command
int DoHelp(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *CONST objv[]) { 
  char* cmd = NULL;
  if (argc == 2) {
    cmd = Tcl_GetString(objv[1]);
  }
  return getActiveShell()->cmdHelp(cmd);
}

int DoLoad(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) { 
  if (argc!=2) {
    Tcl_AppendResult(interp, "Missing program file", NULL);
    return TCL_ERROR;
  }
  else {
    STRING elfFile = (STRING )argv[1];
    if (getActiveShell()->cmdLoadElf(elfFile) == TCL_OK) {
      _last_mem_dump_addr = getActiveShell()->cmdGetPC();
      return TCL_OK;
    }
    else
      return TCL_ERROR;
  }
}

/*
 * DoBackTraceCmd - list all previous function calls from the current address
 */
int DoBackTraceCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) { 
  if (argc!=1) {
    Tcl_AppendResult(interp, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER);
    return TCL_ERROR;
  }
  getActiveShell()->cmdBackTrace();
  return TCL_OK; 
}

/*
 * DoSetWatchCmd - set watchpoint on instruction execution
 */
int DoSetWatchCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) { 
  if (argc!=2) {
    Tcl_AppendResult(interp, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER);
    return TCL_ERROR;
  }
  ADDR addr;
  if (GetAddrFromString(interp, addr, argv[1]) != TCL_OK ) {
    return TCL_ERROR;
  }

  if (strcmp("rwatch", argv[0]) == 0)
    getActiveShell()->cmdSetReadBreak(addr);
  else if (strcmp("watch", argv[0]) == 0)
    getActiveShell()->cmdSetWriteBreak(addr);
  else if (strcmp("awatch", argv[0]) == 0) {
    getActiveShell()->cmdSetReadBreak(addr);
    getActiveShell()->cmdSetWriteBreak(addr);
  }
  return TCL_OK; 
}

/*
 * DoSetBreakCmd - break on instruction execution
 */
int DoSetBreakCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) { 
  if (argc!=2) {
    Tcl_AppendResult(interp, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER, NULL);
    return TCL_ERROR;
  }
  ADDR addr;
  if (GetAddrFromString(interp, addr, argv[1]) != TCL_OK)
    return TCL_ERROR;

  getActiveShell()->cmdSetInstrBreak(addr);
  return TCL_OK; 
}

int DoClearBreakCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) {
  if (argc > 2) {
    Tcl_AppendResult(interp,SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER, NULL);
    return TCL_ERROR;
  }
  
  // The 1st choice is current PC
  ADDR addr = getActiveShell()->cmdGetPC();
      
  if (2==argc && GetAddrFromString(interp, addr, argv[1]) != TCL_OK ) {
    return TCL_ERROR;
  }

  int ret = 0;
  if ( getActiveShell()->cmdClearReadBreak(addr)  == 0)
    ret ++;
  if ( getActiveShell()->cmdClearWriteBreak(addr) == 0)
    ret ++;
  if ( getActiveShell()->cmdClearInstrBreak(addr) == 0)
    ret ++;
  if (!ret) {
    char buf[128];
    sprintf(buf, "No breakpoints at address %#08x", addr);
    Tcl_AppendResult(interp, buf, NULL);
  }
  return TCL_OK; 
}

int DoDeleteBreakCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) {
  if (argc == 1) {
    getActiveShell()->cmdClearAllBreak();
    return TCL_OK;
  }
   
  long brknumber;
  int i;
  for (i=1; i<argc; i++) {
    if (Tcl_ExprLong(interp, argv[i], &brknumber) != TCL_OK ) {
      Tcl_AppendResult(interp, "Invalid breakpoint number:", argv[1], NULL);
      continue;
    }
    if (getActiveShell()->cmdClearBreakByIndex(brknumber) != TCL_OK) {
      Tcl_AppendResult(interp, "No breakpoint #", argv[i], NULL);
      continue;
    }
  }
  return TCL_OK; 
}

int DoEnableBreakCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) {
  if (argc == 1) {
    getActiveShell()->cmdEnableBreak((UINT)-1, true);
    return TCL_OK;
  }
   
  long brknumber;
  int i;
  for (i=1; i<argc; i++) {
    if (Tcl_ExprLong(interp, argv[i], &brknumber) != TCL_OK ) {
      Tcl_AppendResult(interp, "Invalid breakpoint number:", argv[1], NULL);
      continue;
    }
    getActiveShell()->cmdEnableBreak(brknumber, true);
  }
  return TCL_OK; 
}

int DoDisableBreakCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) {
  if (argc == 1) {
    getActiveShell()->cmdEnableBreak((UINT)-1, false);
    return TCL_OK;
  }
   
  long brknumber;
  int i;
  for (i=1; i<argc; i++) {
    if (Tcl_ExprLong(interp, argv[i], &brknumber) != TCL_OK ) {
      Tcl_AppendResult(interp, "Invalid breakpoint number:", argv[1], NULL);
      continue;
    }
    getActiveShell()->cmdEnableBreak(brknumber, false);
  }
  return TCL_OK; 
}

int DoClearRegsCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) {
  if (argc!=1) {
    Tcl_AppendResult(interp, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER, NULL);
    getActiveShell()->printCmdUsage("clreg");
    return TCL_ERROR;
  }
  getActiveShell()->cmdClearRegs();
  return TCL_OK;
}

int DoDisassembly(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) { 
  fprintf(stderr, "This command is deprecated. Please use x command.\n");
  return TCL_OK;
}

int DoNextiCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) { 
  fprintf(stderr, "Not implemented.\n");
  return TCL_OK;
}

/*
 * print(p) command now becomes expression dump command.
 * Usage: print(p) [/f] expression
 *      format character: 
        x Regard the bits of the value as an integer, and print the integer in hexadecimal.
        d Print as integer in signed decimal.
        u Print as integer in unsigned decimal.
        o Print as integer in octal.
        t Print as integer in binary. The letter t stands for two. (not supported yet)
        a Print as an address, same as x.
        c Regard as an integer and print it as a character constant. This prints both the
        numerical value and its character representation. The character representation
        is replaced with the octal escape \nnn for characters outside the 7-bit ascii
        range.
        f Regard the bits of the value as a floating point number and print using typical
        floating point syntax.* Not implemented: symbol table, address, only 32bit integer
*/
int DoPrintCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) { 
static const char *_fmtStr = "xduotacf";
  char fmtChar='\0';
  // check if format is specified and valid
  if (argc>=2 && argv[1][0] == '/') {
    // if the 2nd argument is started with '/', check it
    if ((strlen(argv[1]) != 2) ||(strchr(_fmtStr, argv[1][1])==NULL)) {
      fprintf(stderr, "Invalid format:%s must be one of 'xduota'", argv[1]);
      return TCL_ERROR;
    }
    // fmtChar will be used later 
    if (argv[1][0]=='/') {
      fmtChar = argv[1][1];
      if (fmtChar == 'a')
        fmtChar = 'x';
      if (fmtChar == 't') {
        fprintf(stderr, "binary representation not supported");
        return TCL_ERROR;
      }
      // save it to last format character
      _last_fmt_char = fmtChar;
    }
  }
  // use previous format char if it's legal for print command
  if (!fmtChar && _last_fmt_char && strchr(_fmtStr, _last_fmt_char))
    fmtChar = _last_fmt_char;

  if (argc==2 && strcmp(argv[1], "$") == 0) {
    getActiveShell()->cmdDumpRegs(stdout, 0, "all");
    strcpy(_last_dump_cmd, "$");
    _is_expr = true;
    return TCL_OK;
  }
  
  // build the expression
  char *exprStr = NULL;
  char expr_buf[MAX_DUMP_CMD];
  
  // check if repeat last command
  if ((argc == 1) || ((argc==2) && (argv[1][0] == '/'))) {
//    printf("repeat dump command:%s\n", _last_dump_cmd);
    if (!_last_dump_cmd[0]) {
      return TCL_OK;
    }
    
    // Retrieve the expression from last command buffer if needed
    if (!_is_expr) {
      int newc=0; 
      char **newArgv=NULL;
      /*
       * Commands look like: p word1 word2 ...
       *                 or: p /f word1 word2 ...
       * The expression is "word1 word2 ..."
       */
      if(Tcl_SplitList(interp, _last_dump_cmd, &newc,(const char***)&newArgv) == TCL_OK) {
        SimFatal((newc>=2), ("At least two parameters"));
//        char *newExpr;
        int newArgvIdx=-1;
        
        if (newArgv[1][0]=='/') {
          newc -= 2;
          newArgvIdx = 2;
        } else {
          newc -= 1;
          newArgvIdx = 1;
        }
//          newExpr = Tcl_Concat(newc-2, &newArgv[2]);  // skip both command and format
//        else 
//          newExpr = Tcl_Concat(newc-1, &newArgv[1]);  // skip only command
        int i;
        int cc = 0;
        char newExpr[MAX_DUMP_CMD];
        for (i=0; i<newc; i++) {
          ADDR val;
          if (GetSymbolValue(interp, val, newArgv[newArgvIdx+i]) == TCL_OK)
            cc += sprintf(newExpr+cc, " %#x", val);
          else
            cc += sprintf(newExpr+cc, " %s", newArgv[newArgvIdx+i]);  
        }
        Tcl_Free((char*)newArgv);
        
        SimFatal((cc<MAX_DUMP_CMD-1), ("Internal error:Too many arguments"));
        newExpr[cc] = '\0';
        
//        SimFatal((strlen(newExpr)<MAX_DUMP_CMD-1), ("Internal error:Too many arguments"));
        strcpy(_last_dump_cmd, newExpr);
//        Tcl_Free(newExpr);
        // now the command buffer contains only expression
        _is_expr = true;
      }
      else {
        fprintf(stderr, "can't get expression from history command:%s", _last_dump_cmd);
        return TCL_ERROR;
      }
    }
    
    exprStr = _last_dump_cmd;
  }
  else {
    int exprArgc = argc-1;
    int argvIdx = 1;
    if (argv[1][0] == '/') {
      exprArgc --;
      argvIdx ++;
    }
    int cc = 0;
    int i;
    for (i=0; i<exprArgc; i++) {
      ADDR val;
      if (GetSymbolValue(interp, val, argv[argvIdx+i]) == TCL_OK)
        cc += sprintf(expr_buf+cc, " %#x", val);
      else
        cc += sprintf(expr_buf+cc, " %s", argv[argvIdx+i]);  
    }
    SimFatal((cc<MAX_DUMP_CMD-1), ("Too many arguments\n"));
    expr_buf[cc] = '\0';
//    exprStr = Tcl_Concat(exprArgc, &argv[argvIdx]);

    // This is to avoid future mistake of forgetting free the buffer
//    strcpy(expr_buf, exprStr);
//    Tcl_Free(exprStr);
    
    exprStr = expr_buf;
    // TCL has done variable substitution on this expression, we can't use it again
  }
//  printf("expr string:%s\n", exprStr);
  if (strcmp(exprStr, "$") == 0) {
    if (fmtChar!='x') {
      fprintf(stderr, "Dump of all registers dump is always in hex");
      return TCL_ERROR;
    }
    getActiveShell()->cmdDumpRegs(stdout, 0, "all");
    return TCL_OK;
  }
  
  DWORD val;
  char fmtStr1[8]="%#ld\n";
  // replace the integer type
  if (fmtChar)
    fmtStr1[3] = fmtChar;
  Tcl_Obj *objPtr, *resultPtr;
  objPtr = Tcl_NewStringObj(exprStr, strlen(exprStr));
    int ret = Tcl_ExprObj(interp, objPtr, &resultPtr);
    if (ret == TCL_OK) {
      int len=0;
        const char *resultStr = Tcl_GetStringFromObj(resultPtr, &len);
        char *endp = NULL;
        val = strtoll(resultStr, &endp, 0);
    if (*endp) {
      SimFatal(!endp||!(*endp), ("Invalid integer specified"));
      return TCL_ERROR;
    }
        Tcl_DecrRefCount(resultPtr);  /* done with the result object */
    }
    Tcl_DecrRefCount(objPtr);

//  int ret = Tcl_ExprLong(interp, exprStr, &val);
  if ( ret == TCL_OK) {
    if (fmtChar == 'c')
      fprintf(stdout, "%u \'%c\'\n", (unsigned)(val&0xff), (char)(val&0xff));
    else {
      fprintf(stdout, fmtStr1, val);
    }
  }
  else {
    fprintf(stderr, "Invalid expression:%s\n", exprStr);
  }

  // save the expression
  if (argc > 2 || (argc==2 && argv[1][0]!='/'))
  {
    // save it for repeat later
    strcpy(_last_dump_cmd, Tcl_GetLastCommand());
    _is_expr = false;
  }

  return TCL_OK;
}

int DoDumpFuncCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) {
  if (argc != 2) {
    Tcl_AppendResult(interp, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER, NULL);
    return TCL_ERROR;
  }
  
  FILE *funcFp = fopen(argv[1], "wb");
  if (funcFp == NULL) {
    fprintf(stderr, "Can't open file %s for dumping function list.", argv[1]);
    return TCL_ERROR;
  }
  getActiveShell()->cmdDumpFunc(funcFp);
  fclose(funcFp);
  return TCL_OK;
}

int DoDumpMemCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) {
  if (argc != 4) {
    Tcl_AppendResult(interp, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER, NULL);
    return TCL_ERROR;
  }
  ADDR addr;
  UINT length;
  int ret;
  ret = Tcl_GetInt(interp, argv[1], (int*)&addr);
  if (ret != 0) {
    Tcl_AppendResult(interp, "Invalid address:", argv[1], NULL);
    return TCL_ERROR;
  }
  ret = Tcl_GetInt(interp, argv[2], (int*)&length);
  if (ret != 0) {
    Tcl_AppendResult(interp, "Invalid memory block length:", argv[2], NULL);
    return TCL_ERROR;
  }
  
  FILE *memFp = fopen(argv[3], "wb");
  if (memFp == NULL) {
    fprintf(stderr, "Can't open file %s for saving mem.", argv[3]);
    return TCL_ERROR;
  }
  getActiveShell()->cmdDumpMem(memFp, addr, length);  // 1 for line mode, o for normal
  fclose(memFp);
  return TCL_OK;
}

int DoDumpRegCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) {
  if (argc != 3) {
    Tcl_AppendResult(interp, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER, NULL);
    return TCL_ERROR;
  }
  char *regSetList[4] = {"all", "core", "bb", "h264"};
  int i;
  bool bValidRegSet = false;
  for (i=0; i<4; i++) {
    if (strcasecmp(regSetList[i], argv[1]) == 0) {
      bValidRegSet = true;
      break;
    }
  }
  if (!bValidRegSet) {
    Tcl_AppendResult(interp, "Wrong register set specified", NULL);
    return TCL_ERROR;
  }
  FILE *regFp = fopen(argv[2], "wb");
  if (regFp == NULL) {
    fprintf(stderr, "Can't open file %s for saving registers.", argv[2]);
    return TCL_ERROR;
  }
  getActiveShell()->cmdDumpRegs(regFp, 1, argv[1]); // 1 for line mode, o for normal
  fclose(regFp);
  return TCL_OK;
}

int DoInitMemCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) {
  if (argc != 3) {
    Tcl_AppendResult(interp, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER, NULL);
    return TCL_ERROR;
  }
  ADDR addr;

  if (GetAddrFromString(interp, addr, argv[1]) != TCL_OK ) {
    Tcl_AppendResult(interp, "Invalid memory address:", argv[1], NULL);
    return TCL_ERROR;
  }
  FILE *memFp = fopen(argv[2], "rb");
  if (memFp == NULL) {
    fprintf(stderr, "Can't open file %s for init memory.", argv[2]);
    return TCL_ERROR;
  }
  getActiveShell()->cmdInitMem(memFp, addr);
  fclose(memFp);
  return TCL_OK;
}

int DoInitSramCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) {
  if (argc != 3) {
    Tcl_AppendResult(interp, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER, NULL);
    return TCL_ERROR;
  }
  ADDR addr;
  if (GetAddrFromString(interp, addr, argv[1]) != TCL_OK ) {
    Tcl_AppendResult(interp, "Invalid sram address:", argv[1], NULL);
    return TCL_ERROR;
  }
  FILE *memFp = fopen(argv[2], "rb");
  if (memFp == NULL) {
    fprintf(stderr, "Can't open file %s for init sram.", argv[2]);
    return TCL_ERROR;
  }
  getActiveShell()->cmdInitSRAM(memFp, addr);
  fclose(memFp);

  return TCL_OK;
}

int DoInitRegCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) {
  if (argc != 3) {
    Tcl_AppendResult(interp, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER, NULL);
    return TCL_ERROR;
  }
  char *regSetList[4] = {"all", "core", "bb", "h264"};
  int i;
  bool bValidRegSet = false;
  for (i=0; i<4; i++) {
    if (strcasecmp(regSetList[i], argv[1]) == 0) {
      bValidRegSet = true;
      break;
    }
  }
  if (!bValidRegSet) {
    Tcl_AppendResult(interp, "Wrong register set specified", NULL);
    return TCL_ERROR;
  }
  FILE *regFp = fopen(argv[2], "rb");
  if (regFp == NULL) {
    fprintf(stderr, "Can't open file %s for loading registers.", argv[2]);
    return TCL_ERROR;
  }
  getActiveShell()->cmdInitRegs(regFp, argv[1]);
  fclose(regFp);
  return TCL_OK;
}

int DoDumpRange(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) { 
  ADDR addr;
  UWORD range;
  if (argc!=3) {
    Tcl_AppendResult(interp, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER, NULL);
    return TCL_ERROR;
  }
  int ret = Tcl_GetInt(interp,argv[1], (int*)&range);
  if (ret != TCL_OK)  {
    return TCL_ERROR;
  } 
  if (GetAddrFromString(interp, addr, argv[2]) != TCL_OK) {
    return TCL_ERROR;
  }

  UWORD i;
  int val;
  char buf[1024];
  bool bLineStart = true;
  for (i=0; i<range; i+=4)
  {
    if (bLineStart)
    {
      if (i)
        Tcl_AppendResult(interp, "\n", NULL);
      sprintf(buf, "0x%08x: ", addr+i);
      Tcl_AppendResult(interp, buf, NULL);
      bLineStart = false;
    }
    val = getActiveShell()->cmdReadDataWord(addr+i);
    if (range-i<4)
    {
      if (range-i==1)
        sprintf(buf, "%02x", val&0xff);
      else if (range-i == 2)
        sprintf(buf, "%04x", val&0xffff);
      else if (range-i == 3)
        sprintf(buf, "%04x %02x", val&0xffff, (val>>16)&0xff);
    }
    else 
    {
      sprintf(buf, "%04x %04x ", val&0xffff, (val>>16)&0xffff);
    }
    Tcl_AppendResult(interp, buf, NULL);
    if ((i+4) % 16 == 0) 
    {
      bLineStart = true;
    }
  }
  return TCL_OK;
}

int DoExitCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) { 
  char buf[32]="exit";
  getActiveShell()->cmdExit();
  return Tcl_Eval(interp, buf); 
}

int DoContinueCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) { 
  if (argc>2) {
    fprintf(stderr, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER);
    return TCL_ERROR;
  }
  long ignoreCount = 1;
  if (argc == 2) {
    int ret = Tcl_ExprLong(interp, argv[1], &ignoreCount);
    if (ret != TCL_OK) {
      fprintf(stderr, "Invalid ignore count specified: %s\n", argv[1]);
      return TCL_ERROR;
    }
  }

  RETURN_TO_SHELL;
  
  if (!MultiThreadingMode)
    getActiveShell()->cmdRunSingleElf(FALSE);
  else
    getActiveShell()->cmdRunMultiElf(FALSE);

  fsim_set_prompt();

  return TCL_OK; 
}

int DoRunCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) { 
  if (argc!=1) {
    fprintf(stderr, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER);
    return TCL_ERROR;
  }
  
  RETURN_TO_SHELL;  
    
  if (strcasecmp(argv[0], "prun") == 0) {
    MultiThreadingMode = 1;
    getActiveShell()->cmdRunMultiElf(FALSE);  // should be false
  } else {
    MultiThreadingMode = 0;
    getActiveShell()->cmdRunSingleElf(FALSE);
  }

  fsim_set_prompt();

  return TCL_OK; 
}

int DoRunTraceCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) { 
  if (argc<2) {
    Tcl_AppendResult(interp, "Missing trace file", NULL);
    return TCL_ERROR;
  }

  STRING file = (STRING )argv[1];
  int retv = getActiveShell()->cmdRunTrace(file, argc >= 3);
  fsim_set_prompt();
  
  return retv; 
}

int DoRerunCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) { 
  if (argc!=1) {
    Tcl_AppendResult(interp, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER, NULL);
    return TCL_ERROR;
  }
  
  RETURN_TO_SHELL;
  
  if (!MultiThreadingMode)
    getActiveShell()->cmdRerunSingleElf(FALSE);
  else
    SimFatal((0), ("Not implemented\n"));//getActiveShell()->cmdRerunMultiElf(FALSE);
  return TCL_OK; 
}

int DoInfoCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { 
  if (objc < 2) {
    Tcl_AppendResult(interp, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER, NULL);
    return TCL_ERROR;
  }
  
  int len;
  if (strcasecmp("dma", Tcl_GetStringFromObj(objv[1], &len)) == 0) {
    if (objc < 3) {
      Tcl_AppendResult(interp, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER, NULL);
      return TCL_ERROR;
    }
    
    if (strcasecmp("counter", Tcl_GetStringFromObj(objv[2], &len)) == 0) {
      UINT df = 0;
      if (objc > 3 && (strcasecmp("hex", Tcl_GetStringFromObj(objv[3], &len)) == 0)) 
        df = 0x8000;
      getActiveShell()->cmdShowDmaTraffic(df);      
    } else {
      Tcl_AppendResult(interp, "Error: Invalid DMA info parameter", NULL);
      return TCL_ERROR;
    }

    return TCL_OK;
  }

  if (objc != 2) {
    Tcl_AppendResult(interp, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER, NULL);
    return TCL_ERROR;
  }
  if (strstr("breakpoints b break watch watchpoints w", Tcl_GetStringFromObj(objv[1], &len))) {
    getActiveShell()->cmdShowBreakPoints();
  } else if (strcasecmp("fsimvars", Tcl_GetStringFromObj(objv[1], &len)) == 0 ) {
    Tcl_AppendResult(interp, "VAR:", VAR_ACTIVE_THREAD_NAME, "  TYPE: string.  Value: 'BB' or 'Core'.\n", NULL);
    Tcl_AppendResult(interp, "VAR:", VAR_VERBOSE_NAME, " TYPE: integer. Value: 0..4.\n", NULL);
    Tcl_AppendResult(interp, "VAR:", VAR_MULTI_THREAD_NAME, 
      "      TYPE: integer. Value: 0 - single thread mode; 1 multithreading mode.", NULL);
  } else if (strcasecmp("registers", Tcl_GetStringFromObj(objv[1], &len)) == 0) {
    char buf[1024];
    getActiveShell()->cmdGetRegisterNames(buf, 1024);
    char *p = strrchr(buf, '\n');
    if (p && (!*(p+1)))
      *p = '\0';
    Tcl_AppendResult(interp, buf, NULL);
  } else {
    return Tcl_InfoObjCmd(clientData, interp, objc, objv);
  }
  return TCL_OK; 
}

int DoExecSteps(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) { 
  if (argc>3)
  {
    Tcl_AppendResult(interp, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER, NULL);
    return TCL_ERROR;
  }
  UWORD steps = 1;
  UWORD addr = ADDR_NOT_SPECIFIED;
  if (argc>=2) {
    int ret = Tcl_GetInt(interp, argv[1], (int*)&steps);
    if (ret != TCL_OK)
    {
      Tcl_AppendResult(interp, "Invalid step # specified:", argv[1], NULL);
      return TCL_ERROR;
    } 
  }
  if (argc==3) {
    if ( Tcl_GetInt(interp, argv[2], (int *)&addr) != TCL_OK)
    {
      Tcl_AppendResult(interp, "Invalid address specified:", argv[2], NULL);
      return TCL_ERROR;
    }
  }

  RETURN_TO_SHELL;
  if (strcasecmp(argv[0], "pstep") == 0||strcasecmp(argv[0], "ps") == 0) {
    MultiThreadingMode = EXEC_PARALLEL;
  }
  else {
    MultiThreadingMode = EXEC_SINGLE;
  } 
  if (getActiveShell()->cmdGetElf()) 
    getActiveShell()->cmdStepElf(steps, FALSE, MultiThreadingMode);
  else
    getActiveShell()->cmdRunMem(addr, steps, FALSE);

  fsim_set_prompt();

  return TCL_OK;
}

int DoExecAndAsm(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) { 
  if (argc>3)
  {
    Tcl_AppendResult(interp, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER, NULL);
    return TCL_ERROR;
  }
  UWORD steps = 1;
  UWORD addr = ADDR_NOT_SPECIFIED;
  
  // # of steps are specified
  if (argc>=2) {
    int ret = Tcl_GetInt(interp, argv[1], (int*)&steps);
    if (ret != TCL_OK)
    {
      Tcl_AppendResult(interp, "Invalid step # specified:", argv[1], NULL);
      return TCL_ERROR;
    } 
  }

  // starting address is specified
  if (argc==3) {
    if ( GetAddrFromString(interp, addr, argv[2]) != TCL_OK) {
      return TCL_ERROR;
    }
  }

  RETURN_TO_SHELL;
  if (strcasecmp(argv[0], "psd") == 0) {
    MultiThreadingMode = EXEC_PARALLEL;
  }
  else {
    MultiThreadingMode = EXEC_SINGLE;
  }

  // Execute # of steps from specified address
  if (getActiveShell()->cmdGetElf()){
    getActiveShell()->cmdStepElf(steps, TRUE, MultiThreadingMode);
  }
  else
  {
    if(argc != 3)
      printf("No ELF object found, and no memory address specified by user\n");
    else
      getActiveShell()->cmdRunMem(addr, steps, true);
  }

  fsim_set_prompt();

  return TCL_OK;
}

int DoSetCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) { 
  if (argc<2)
  {
    Tcl_AppendResult(interp, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER, NULL);
    return TCL_ERROR;
  }
  char *endp=NULL;
  if(argc==3 && strcasecmp(argv[1], "workpath")==0)
  {
    if(chdir(argv[2])<0)
    {
      fprintf(stderr, "Invaild work path.");
      return TCL_ERROR;
    } 
    return TCL_OK;  
  }
  if (argc >= 2 && (strcasecmp(argv[1], "verboselevel") == 0)) {
    UINT val = 0;

    if(argc == 2)
      val = 0;
    else if(argc == 3)
      val = atoi(argv[2]);
    else
    {
      fprintf(stderr, "Invalid Verbose Level.");
      return TCL_ERROR;
    }

    getActiveShell()->VerboseLevel(val);
  }
  else if (argc >= 2 && (strcasecmp(argv[1], "dma") == 0)) {
    if (argc > 3 && (strcasecmp(argv[2], "counter") == 0) && (strcasecmp(argv[3], "0") == 0)) {
      getActiveShell()->cmdResetDmaTraffic();
      return TCL_OK;
    }
    else {
      Tcl_AppendResult(interp, "Error: Invalid set dma parameter\n\tUse \"set dma counter 0\"", NULL);
      return TCL_OK;
    }
  }
  else if (argc==3 && (strcasecmp(argv[1], "sharehigh")==0))
  {
    UWORD val;
    val = strtoll(argv[2], &endp, 0);
    if (*endp) {
      Tcl_AppendResult(interp, "Invalid address specified:", argv[2], NULL);
      return TCL_ERROR;
    }
    getActiveShell()->cmdSetShareMemHigh(val);
  }
  else if (argc==3 && (strcasecmp(argv[1], "sharelow")==0))
  {
    UWORD val;
    val = strtoll(argv[2], &endp, 0);
    if (*endp) {
      Tcl_AppendResult(interp, "Invalid address specified:", argv[2], NULL);
      return TCL_ERROR;
    }
    getActiveShell()->cmdSetShareMemLow(val);
  }
  else if (argc==3 && getActiveShell()->isValidRegName((const STRING)argv[1])) {
  // Check if it's a register
    UDWORD val = 0;
    
    if (fsim_is_reg_readonly(argv[1])) {
      fprintf(stdout, "Failed to set readonly register:%s", argv[1]);
      return TCL_ERROR;
    }
    val = strtoll(argv[2], &endp, 0);
    if (*endp) {
      Tcl_AppendResult(interp, "Invalid integer specified:", argv[2], NULL);
      return TCL_ERROR;
    }
    
    char* p = (char*)argv[1];
    if (argv[1][0] == '$') p++; // This seems not work. TCL will interpret $xxxx.
    if (!*p) {
      Tcl_AppendResult(interp, "Register name missing:", argv[1], NULL);
      return TCL_ERROR;
    } 
//    printf("set reg %s to 0x%08llx\n", p, val);
    if (getActiveShell()->cmdSetReg(p, val)==0) {
      return TCL_OK;
    }
    else {
      Tcl_AppendResult(interp, "Can't set register %s to %s", argv[1], argv[2], NULL);
      return TCL_ERROR;
    }
  } else if (argc==3 && (strcmp(argv[1], VAR_ACTIVE_THREAD_NAME) == 0)) {
    // activate thread
    if (strcasecmp(argv[2], VAR_CORE_THREAD_NAME) == 0) {
      // other processing follows
      getActiveShell()->cmdSetThread(THREAD_ID_0);
    } else if (strcasecmp(argv[2], VAR_BB_THREAD_NAME) == 0) {
      // other processing follows
      getActiveShell()->cmdSetThread(THREAD_ID_1);
    } else if (strcasecmp(argv[2], VAR_SL2_TH0_THREAD_NAME) == 0) {
      getActiveShell()->cmdSetThread(THREAD_ID_0);
    } else if (strcasecmp(argv[2], VAR_SL2_TH1_THREAD_NAME) == 0) {
      getActiveShell()->cmdSetThread(THREAD_ID_1);
    } else if (strcasecmp(argv[2], VAR_SL2_TH2_THREAD_NAME) == 0) {
      getActiveShell()->cmdSetThread(THREAD_ID_2);
    } else if (strcasecmp(argv[2], VAR_SL2_TH3_THREAD_NAME) == 0) {
      getActiveShell()->cmdSetThread(THREAD_ID_3);      
    } else if (strcasecmp(argv[2], VAR_SL2_TH4_THREAD_NAME) == 0) {
      getActiveShell()->cmdSetThread(THREAD_ID_4);
    } else {
      fprintf(stderr, "Invalid thread name");
      return TCL_ERROR;
    }
    strcpy(ActiveThreadName, argv[2]);
    fsim_set_prompt();
    getActiveShell()->cmdLinkRegisters();
  }else if (argc==3 && (strcasecmp(argv[1], "lcd") == 0)) {
    // activate thread
    if (strcasecmp(argv[2], "on") == 0) {
      getActiveShell()->cmdLcdSwitch(TRUE);
      
    } else if (strcasecmp(argv[2], "off") == 0) {
      getActiveShell()->cmdLcdSwitch(FALSE);
      
    } else {
      fprintf(stderr, "Invalid LCD state:%s", argv[2]);
      return TCL_ERROR;
    }
    return TCL_OK;
  }

   else if (argc==3 && (strcmp(argv[1], VAR_MULTI_THREAD_NAME) == 0)) {
    int mode;
    if ((Tcl_GetInt(interp, argv[2], &mode) != TCL_OK) || (mode!=0 && mode!=1)) {
      Tcl_AppendResult(interp, "multithreading mode must be 0 or 1", NULL);
      return TCL_ERROR;
    }
    MultiThreadingMode = mode;
    return TCL_OK;
  } else if (argc==3 && (strcmp(argv[1],"quicktrace")==0)){
    if (strcasecmp(argv[2], "on") == 0)
    {
      getActiveShell()->cmdLogQuickTrace(true);
    }
    else if (strcasecmp(argv[2], "off") == 0)
    {
      getActiveShell()->cmdLogQuickTrace(false);
    }
    else{
      fprintf(stderr,"Invalid ignorelog state:%s",argv[2]);
      return TCL_ERROR;
    }
    return TCL_OK;
  }else if (argc>=3 && (strcmp(argv[1],"ignoretrace")==0)){
    char *p = NULL;
    if (argc==4) p = (char*)argv[3];
    if (strcasecmp(argv[2], "on") == 0)
    {
      getActiveShell()->cmdLogIgnoreTrace(true,p);
    }
    else if (strcasecmp(argv[2], "off") == 0)
    {
      getActiveShell()->cmdLogIgnoreTrace(false,NULL);
    }
    else{
      fprintf(stderr,"Invalid ignorelog state:%s",argv[2]);
      return TCL_ERROR;
    }
    return TCL_OK;
  } else if (argc>=3 && (strcmp(argv[1],"focustrace")==0)){
    char *p = NULL;
    if (argc==4) p = (char*)argv[3];
    if (strcasecmp(argv[2], "on") == 0)
    {
      getActiveShell()->cmdLogFocusTrace(true,p);
    }
    else if (strcasecmp(argv[2], "off") == 0)
    {
      getActiveShell()->cmdLogFocusTrace(false,NULL);
    }
    else{
      fprintf(stderr,"Invalid focuslog state:%s",argv[2]);
      return TCL_ERROR;
    }
    return TCL_OK;    
  } else if (argc==3 && (strcmp(argv[1], OS_THREAD_ID_SYMBOL) == 0)) {
    getActiveShell()->cmdLogUserThreadIdSymbol((STRING)argv[2]);
    return TCL_OK;
  } else if (argc>=3 && (strcmp(argv[1], "logging") == 0)) {
    if (argc==3 && (strcmp(argv[2], "on") == 0)) {
      // start all logging
      getActiveShell()->cmdLogEnableSwitch(true);
      return TCL_OK;
    } else if (argc==3 && (strcmp(argv[2], "off") == 0)) {
      // stop all logging
      getActiveShell()->cmdLogEnableSwitch(false);
      return TCL_OK;
    } else if (argc==3 && (strcmp(argv[2], "suspend") == 0)) {
      // suspend all logging
      getActiveShell()->cmdLogResumeSwitch(false);
      return TCL_OK;
    } else if (argc==3 && (strcmp(argv[2], "resume") == 0)) {
      // resume all logging
      getActiveShell()->cmdLogResumeSwitch(true);
      return TCL_OK;
    } else if (argc>=4 && (strcmp(argv[2], "cbus") == 0)) {
      char *p = NULL;
      if (argc==5) p = (char*)argv[4];
      if (strcmp(argv[3], "on")==0) {
        // enable cbus logging
        getActiveShell()->cmdLogCbus(true, p);
        return TCL_OK;
      } else if ((argc==4) && strcmp(argv[3], "off")==0) {
        // disable cbus logging
        getActiveShell()->cmdLogCbus(false);
        return TCL_OK;
      }
    } else if (argc>=3 && (strcmp(argv[2], "reg") == 0)) {
      char *p = NULL;
      if (argc==5) p = (char*)argv[4];
      if (strcmp(argv[3], "on")==0 && argc>=4) {
        // enable reg logging
        getActiveShell()->cmdLogRegWrite(true, p);
        return TCL_OK;
      } else if (argc==4 && strcmp(argv[3], "off")==0) {
        // disable reg logging
        getActiveShell()->cmdLogRegWrite(false);
        return TCL_OK;
      }
    } else if (argc>=3 && (strcmp(argv[2], "task") == 0)) {
      char *p = NULL;
      if (argc==5) p = (char*)argv[4];
      if (strcmp(argv[3], "on")==0 && argc>=4) {
        // enable trace logging with task id
        getActiveShell()->cmdLogTaskTrace(true, p);
        return TCL_OK;
      } else if (argc==4 && strcmp(argv[3], "off")==0) {
        // disable trace logging with task id
        getActiveShell()->cmdLogTaskTrace(false);
        return TCL_OK;
      }
    } else if (argc>=3 && (strcmp(argv[2], "stack") == 0)) {
      if (strcmp(argv[3], "on")==0 && argc>=4) {
        // enable trace logging
        getActiveShell()->cmdLogStack(true);
        return TCL_OK;
      } else if (argc==4 && strcmp(argv[3], "off")==0) {
        // disable trace logging
        getActiveShell()->cmdLogStack(false);
        return TCL_OK;
      }
    }else if (argc>=3 && (strcmp(argv[2], "trace") == 0)) {
      char *p = NULL;
      if (argc==5) p = (char*)argv[4];
      if (strcmp(argv[3], "on")==0 && argc>=4) {
        // enable trace logging
        getActiveShell()->cmdLogTrace(true, p);
        return TCL_OK;
      } else if (argc==4 && strcmp(argv[3], "off")==0) {
        // disable trace logging
        getActiveShell()->cmdLogTrace(false);
        return TCL_OK;
      }
    } else if (argc>=3 && (strcmp(argv[2], "result") == 0)) {
      char *p = NULL;
      if (argc >= 5) 
        p = (char*)argv[4];
      if (argc>=4 && strcmp(argv[3], "on")==0) {        
        getActiveShell()->cmdLogRegMem(true, p);
        return TCL_OK;
      } else if (argc==4 && strcmp(argv[3], "off")==0) {
        getActiveShell()->cmdLogRegMem(false);
        return TCL_OK;
      }
    } else if (argc>=3 && (strcmp(argv[2], "disasm") == 0)) {
      char *p = NULL;
      if (argc==5) p = (char*)argv[4];
      if (strcmp(argv[3], "on")==0 && argc>=4) {
        // enable disasm logging
        getActiveShell()->cmdLogDisasm(true, p);
        return TCL_OK;
      } else if (argc==4 && strcmp(argv[3], "off")==0) {
        // disable disasm logging
        getActiveShell()->cmdLogDisasm(false);
        return TCL_OK;
      }
    } else if (argc>=3 && (strcmp(argv[2], "instrcnt") == 0)) {
      if (argc>=4 && strcmp(argv[3], "on")==0) {
        // enable disasm logging
        if((argc == 5) && (strcmp(argv[4], "all") == 0))
          getActiveShell()->cmdLogInstrCnt(true, true);
        else
          getActiveShell()->cmdLogInstrCnt(true, false);
        return TCL_OK;
      } else if (argc==4 && strcmp(argv[3], "off")==0) {
        // disable disasm logging
        getActiveShell()->cmdLogInstrCnt(false, false);
        return TCL_OK;
      }
    }else if (argc>=3 && (strcmp(argv[2], "call") == 0)) {
      char *p = NULL;
      if (argc==5) p = (char*)argv[4];
      if (argc>=4 && strcmp(argv[3], "on")==0) {
        // enable disasm logging
        getActiveShell()->cmdLogCall(true, p);
        return TCL_OK;
      } else if (argc==4 && strcmp(argv[3], "off")==0) {
        // disable disasm logging
        getActiveShell()->cmdLogCall(false);
        return TCL_OK;
      }
    } else if ((argc == 4) && (strcmp(argv[2], "redirect") == 0)) {
      if (strcmp(argv[3], "on") == 0 ) {
        getActiveShell()->cmdEnableRedirect(true);
      } else if (strcmp(argv[3], "off") == 0) {
        getActiveShell()->cmdEnableRedirect(false);
      }
    }
    
    fprintf(stderr, "Invalid command syntax. Missing filename?", argc);
    return TCL_ERROR;
  }else if (argc>=3 && (strcasecmp(argv[1], "execmode") == 0)) {
    if (argc>=3 && (strcmp(argv[2], "skipfork") == 0)) {
      char *p = NULL;
      if (argc==5) p = (char*)argv[4];
      if (strcmp(argv[3], "on")==0) {
        // enable cbus logging
        getActiveShell()->cmdSetExecMode(0, TRUE);
        return TCL_OK;
      } else if ((argc==4) && strcmp(argv[3], "off")==0) {
        // disable cbus logging
        getActiveShell()->cmdSetExecMode(0, FALSE);
        return TCL_OK;
      }
    }
    //fprintf(stderr, "Invalid command syntax. Mode name (%s) not find.", argv[2]);
    //return TCL_ERROR; 
  }else if(argc>=2 && ( strcmp( argv[ 1 ], "args" )  == 0)) {
    getActiveShell()->cmdSetArgument( argc, argv );
    return TCL_OK;    
  }
  const char* retObj;
  if (argc == 2) {
    retObj = Tcl_SetVar(interp, argv[1], NULL, TCL_LEAVE_ERR_MSG);
  } else {
    // Not a register name, call normal TCL procedure
    char *newCmd;
    newCmd = Tcl_Concat(argc-2, &argv[2]);
    if (newCmd) {
      retObj = Tcl_SetVar(interp, argv[1], newCmd, TCL_LEAVE_ERR_MSG);
      Tcl_Free(newCmd);
    }
  }
  if (!retObj) {
    return TCL_ERROR;
  }
  return TCL_OK;
}

int DoSetMemByte(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) { 
  if (argc!=3)
  {
    Tcl_AppendResult(interp, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER, NULL);
    return TCL_ERROR;
  }
  ADDR addr;
  UWORD val;
  int ret = GetAddrFromString(interp, addr, argv[1]);
  if (ret != TCL_OK) {
    return TCL_ERROR;
  } 
  ret = Tcl_GetInt(interp, argv[2], (int *)&val);
  if (ret != TCL_OK)
  {
    Tcl_AppendResult(interp, "Invalid value specified:", argv[2], NULL);
    return TCL_ERROR;
  }
  if (val & 0xffffff00)
  {
    Tcl_AppendResult(interp, "Value must be a byte value: 0..255", NULL);
    return TCL_ERROR;
  }
  val &= 0xff;

  UWORD range=1;
  if (argc==4) {
    ret = Tcl_GetInt(interp, argv[3], (int *)&range);
    if (ret != TCL_OK)
    {
      Tcl_AppendResult(interp, "Invalid range specified:", argv[3], NULL);
      return TCL_ERROR;
    }
  }

  UINT i;
  for (i=0; i<range; i++)
    getActiveShell()->cmdWriteDataByte(addr+i, val);

  return TCL_OK;
}

int DoSetMemWord(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) { 
  if (argc!=3 && argc!=4)
  {
    Tcl_AppendResult(interp, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER, NULL);
    return TCL_ERROR;
  }
  UWORD addr;
  UWORD val;
  int ret = GetAddrFromString(interp, addr, argv[1]);
  if (ret != TCL_OK) {
    return TCL_ERROR;
  } 
  ret = Tcl_GetInt(interp, argv[2], (int *)&val);
  if (ret != TCL_OK) {
    Tcl_AppendResult(interp, "Invalid value specified:", argv[2], NULL);
    return TCL_ERROR;
  }
  UWORD range=1;
  if (argc==4) {
    ret = Tcl_GetInt(interp, argv[3], (int *)&range);
    if (ret != TCL_OK)
    {
      Tcl_AppendResult(interp, "Invalid range specified:", argv[3], NULL);
      return TCL_ERROR;
    }
  }
  UINT i;
  for (i=0; i<range; i+=4) {
    getActiveShell()->cmdWriteDataWord(addr+i, val);
  }
  return TCL_OK;
}

int DoSetRegister(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) { 
  fprintf(stderr, "Not implemented. Please use set command.\n");
  return TCL_OK;
}

int DoStepiCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) { 
  if (argc>2) {
    fprintf(stderr, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER);
    return TCL_ERROR;
  }
  int steps = 1;
  if (argc == 2) {
    int ret = Tcl_GetInt(interp, argv[1], &steps);
    if (ret != TCL_OK) {
      fprintf(stderr, "Invalid steps specified:%s\n", argv[1]);
      return TCL_ERROR;
    }
  }
  ADDR addr = getActiveShell()->cmdGetPC();
  if (strcasecmp(argv[0], "pstepi") == 0||strcasecmp(argv[0], "psi") == 0) {
    MultiThreadingMode = EXEC_PARALLEL;
  }
  else {
    MultiThreadingMode = EXEC_SINGLE;
  }   
  ExecSteps(addr, steps, 1);
  return TCL_OK; 
}

int DoUse(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) { 
  if (argc != 2)
  {
    Tcl_AppendResult(interp, SHELL_ERROR_MSG_WRONG_ARGUMENT_NUMBER, NULL);
    getActiveShell()->printCmdUsage("use");
    return TCL_ERROR;
  }
  if (strcmp(argv[1], "gpr16") == 0)
  {
    getActiveShell()->cmdSetThread(THREAD_ID_1);
  }
  else if (strcmp(argv[1], "gpr32") == 0)
  {
    getActiveShell()->cmdSetThread(THREAD_ID_0);
  }
  else
  {
    Tcl_AppendResult(interp, "Wrong gpr set!", NULL);
    return TCL_ERROR;
  }
  fsim_set_prompt();
  getActiveShell()->cmdLinkRegisters();
  return TCL_OK;
}

WORD comReadWord(ADDR addr, bool bPhysicalMem=false)
{
  if (bPhysicalMem) {
    return getActiveShell()->cmdReadDataWord(addr);
  } else {
    return getActiveShell()->cmdReadDataWord(addr);
  }
}

WORD comReadHword(ADDR addr, bool bPhysicalMem=false)
{
  if (bPhysicalMem) {
    return getActiveShell()->cmdReadDataHword(addr);
  } else {
    return getActiveShell()->cmdReadDataHword(addr);
  }
}

BYTE comReadByte(ADDR addr,  bool bPhysicalMem=false)
{
  if (bPhysicalMem) {
    return getActiveShell()->cmdReadDataByte(addr);
  } else {
    return getActiveShell()->cmdReadDataByte(addr);
  }
}

void DumpMemory(ADDR addr, int count, int unitSize, char fmtChar, bool bPhysicalMem=false)
{
//  printf("DumpMemory addr:%#08x count:%d size:%d fmt:%c\n",
//    addr, count, unitSize, fmtChar);
  int unitsPerLine = 16;
  int i;
  DWORD val;
  DWORD val2;
  if ('a' == fmtChar) {
    // address
    unitSize = 4;
    fmtChar = 'x';
    unitsPerLine = 8;
    for (i=0; i<count; i++) {
      if (i%unitsPerLine == 0)
        fprintf(stdout, "%#04x: ", addr+i*4);
      fprintf(stdout, "%#04x ", comReadWord(addr+i*4, bPhysicalMem));
      if (i%unitsPerLine == unitsPerLine-1)
        fprintf(stdout, "\n");
    }
  }
  else if ( 'u' == fmtChar || 'd' == fmtChar || 'x' == fmtChar) {
    // Integers
    unitsPerLine = 16/unitSize;
    if (unitsPerLine<8)
      unitsPerLine = 8;
    if (unitSize == 8)
      unitsPerLine = 4;
    for (i=0; i<count; i++) {
      if (i%unitsPerLine == 0)
        fprintf(stdout, "%#04x: ", addr+i*unitSize);
        
      if (unitSize == 1) {
        val = comReadByte(addr+i, bPhysicalMem);
        val &= 0xff;
        if ('x' == fmtChar)
          fprintf(stdout, "%0*x ", unitSize*2, val);
        else {
          char fmtStr[8] ="%d ";
          fmtStr[1] = fmtChar;
          fprintf(stdout, fmtStr, val);
        }
      }
      else if (unitSize == 2) {
        val = comReadHword(addr+i*unitSize, bPhysicalMem);
        val &= 0xffff;
        if ('x' == fmtChar)
          fprintf(stdout, "%0*x ", unitSize*2, val);
        else {
          char fmtStr[8] ="%d ";
          fmtStr[1] = fmtChar;
          fprintf(stdout, fmtStr, val);
        }
      }
      else if (unitSize == 4) {
        val = comReadWord(addr+i*unitSize, bPhysicalMem);
        val &= 0xffffffff;
        if ('x' == fmtChar)
          fprintf(stdout, "%0*x ", unitSize*2, val);
        else {
          char fmtStr[8] ="%d ";
          fmtStr[1] = fmtChar;
          fprintf(stdout, fmtStr, (WORD)val);
        }
      }
      else if (unitSize == 8) {
        val = comReadWord(addr+i*unitSize, bPhysicalMem);
        val2 = comReadWord(addr+ (i*unitSize) + 4, bPhysicalMem);
        if ('x' == fmtChar) {
          fprintf(stdout, "%08x%08x ", (WORD)val, (WORD)val2);
        }
        else {
          unsigned long long v = val2;
          v = (unsigned long long )val + (v<<32);
          char fmtStr[8] ="%lld ";
          fmtStr[3] = fmtChar;
          fprintf(stdout, fmtStr, v);
        }
      }
      
      if (i%unitsPerLine == unitsPerLine-1)
        fprintf(stdout, "\n");
    }
  }
  else if ('c' == fmtChar || 's' == fmtChar) {
    // chars
    unitSize = 1;
    fmtChar = 'c';
    unitsPerLine = 16;
    char valBuf[128];
    char charBuf[32];
    int cc = 0;
    for (i=0; i<count; i++) {
      if (i%unitsPerLine == 0) {
        fprintf(stdout, "%#04x: ", addr+i);
        cc=0;
      }
      char ch = comReadByte(addr+i, bPhysicalMem);
      sprintf(valBuf+cc*3, "%02x ", (unsigned)ch&0xff);
      if (isprint(ch))
        charBuf[cc++] = ch;
      else
        charBuf[cc++] = '.';
      
      if (i%unitsPerLine == unitsPerLine-1 || i>=count-1) {
        valBuf[cc*3] = '\0';
        charBuf[cc] = '\0';
        fprintf(stdout, "%s \t%s\n", valBuf, charBuf);
      }
    }
  }
  else if ('i' == fmtChar) {
    getActiveShell()->cmdDisassembly(addr, count);
  }
  else {
    fprintf(stderr, "Not implemented\n");
    return;
  }
  
  fprintf(stdout, "\n");
  _last_mem_dump_addr = addr + count * unitSize;
}

void SetMemory(ADDR addr, DWORD value, int count, int unitSize, bool bPhysicalMem=false)
{
  int i;
  if (unitSize == 1) {
    for (i=0; i<count; i++) {
      if (bPhysicalMem) 
        getActiveShell()->cmdWriteDataByte(addr+i, (BYTE)value);
      else
        getActiveShell()->cmdWriteDataByte(addr+i, (BYTE)value);
    }
  } else if (unitSize == 4) {
    for (i=0; i<count; i++) {
      if (bPhysicalMem) 
        getActiveShell()->cmdWriteDataWord(addr+i*unitSize, value);
      else
        getActiveShell()->cmdWriteDataWord(addr+i*unitSize, value);
    }
  } else {
    fprintf(stderr, "Unit size not supported\n");
  }
}

int DoPrintMemCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) { 
static const char *_print_mem_fmt_str="xudotacmsi";

  UINT repeatCount = 0;
  UINT unitSize = 0;
  long addr=0;
  long value=0;
  int nextArg=1;
  int ret;
  bool bPhysicalMem = false;
  
  if (strcmp(argv[0], "xp") == 0) bPhysicalMem = true;
//  if ( bPhysicalMem ) printf("Physical memory\n");
  
  // check format
  char fmtChar='\0';

  if ((argc>3 && argv[1][0]!='/') || (argc>4 && argv[1][0]=='/')) {
    fprintf(stderr, "Wront # of arguments\n");
    return TCL_ERROR;
  }
  
  // check if format is specified and valid
  if (argc>=2 && argv[1][0] == '/') {
    nextArg = 2;
    if (strlen(argv[1]) == 1) {
      fprintf(stderr, "Invalid format string:%s\n", argv[1]);
      return TCL_ERROR;
    }
    char *p = (char*)(argv[1]+strlen(argv[1])-1);
    // check if last char is unit size char
    // unit size only affect integer
    if (*p) {
      const char *sizeStr = "bhwg";
      char *q = strchr(sizeStr, *p);
      if (q) {
        unitSize = 1<<(q-sizeStr);
        *p-- = '\0';  // discard the unit size character
      }
    }
//    if (p!=argv[1]) printf("format char is %c\n", *p);
    // next parameter must be format if present
    if (p!=argv[1] && (strchr(_print_mem_fmt_str, *p)!=NULL)) {
      fmtChar = *p;
      if (fmtChar == 't') {
        fprintf(stderr, "binary representation not supported\n");
        return TCL_ERROR;
      }
      
      *p--='\0';
    }
    // check for repeat count
    p = (char *)(argv[1]+1);
    if (*p && isdigit(*p)) {
      char *q=NULL;
      repeatCount = strtoll(p, &q, 0);
      if (q == p) {
        // no repeat count specified
        fprintf(stderr, "No repeat count\n");
      } else if (*q) {
        fprintf(stderr, "Invalid format string specified:%s\n", argv[1]);
        return TCL_ERROR;
      }
    }
  }
  // save
  if (fmtChar) _last_fmt_char = fmtChar;
  if (unitSize) _last_unit_size = unitSize;
  if (repeatCount) _last_repeat_count = repeatCount;
      
  // use previous format char if it's legal for x command
  if (!fmtChar && _last_fmt_char && strchr(_print_mem_fmt_str, _last_fmt_char))
    fmtChar = _last_fmt_char;
  if (!fmtChar)
    fmtChar = 'u';
    
  if (!unitSize && _last_unit_size)
    unitSize = _last_unit_size;
  if (!addr) {
    if (fmtChar == 'i' && _last_mem_dump_addr==0)
      addr = getActiveShell()->cmdGetPC();
    else
      addr = _last_mem_dump_addr;
  }

  if (0 == repeatCount)
    repeatCount = _last_repeat_count;

  // check for address parameter
  if (nextArg>=argc) {
    // Dump after previous address
    DumpMemory(addr, repeatCount, unitSize, fmtChar, bPhysicalMem);
    return TCL_OK;
  }
  // get address
  if (GetAddrFromString(interp, (ADDR&)addr, argv[nextArg]) != TCL_OK) {
    return TCL_ERROR;
  }
  _last_mem_dump_addr = addr;
  nextArg++;
  
  // check for value parameter
  if (nextArg >= argc) {
    // dump memory
    DumpMemory(addr, repeatCount, unitSize, fmtChar, bPhysicalMem);
    return TCL_OK;
  }
  
  // value parameter is present
  ret = Tcl_ExprLong(interp, argv[nextArg], &value);
  if (ret != TCL_OK) {
    fprintf(stderr, "Invalid value specified: %s", argv[nextArg]);
    return TCL_ERROR;
  }
  // set memory
  SetMemory(addr, value, repeatCount, unitSize, bPhysicalMem);
  return TCL_OK;
}

int DoUnitTest(ClientData clientData, Tcl_Interp *interp, int argc, const char* argv[]) {
  int v = getActiveShell()->cmdGetExecStatus();
  fprintf(stdout, "exec status:%x\n", v);
  return TCL_OK;
} 

static void
catch_signal (INT sig, INT error_num)
{
  fprintf(stdout, "CTRL-C\n");
  fprintf(stdout, "\n%s", Tcl_GetVar(gInterp, "sl_prompt", TCL_GLOBAL_ONLY));
  getActiveShell()->cmdInterruptCtrlC();
}

int Tcl_AppInit(Tcl_Interp *interp) {
  if (Tcl_CreateObjCommand(interp, "help", DoHelp, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "awatch", DoSetWatchCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "b", DoSetBreakCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "break", DoSetBreakCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "bt", DoBackTraceCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "c", DoContinueCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "cl", DoClearBreakCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "clear", DoClearBreakCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "clreg", DoClearRegsCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "cont", DoContinueCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "continue", DoContinueCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "d", DoDeleteBreakCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "delete", DoDeleteBreakCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "dis", DoDisassembly, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "disable", DoDisableBreakCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "dumpfunc", DoDumpFuncCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "dumpmem", DoDumpMemCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "dumpreg", DoDumpRegCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "enable",  DoEnableBreakCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateObjCommand(interp, "info", DoInfoCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "initmem", DoInitMemCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "initreg", DoInitRegCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "initsram", DoInitSramCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "load", DoLoad, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "ni", DoNextiCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "nexti", DoNextiCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "p", DoPrintCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "pr", DoDumpRange, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "print", DoPrintCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "prun", DoRunCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "ps", DoExecSteps, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "psd", DoExecAndAsm, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "psi", DoStepiCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "pstep", DoExecSteps, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "pstepi", DoStepiCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "q", DoExitCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
//  if (Tcl_CreateCommand(interp, "exit", DoExitCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL)  return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "quit", DoExitCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL)  return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "r", DoRunCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL)  return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "rerun", DoRerunCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "rr", DoRerunCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "run", DoRunCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "rwatch", DoSetWatchCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "s", DoExecSteps, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "sd", DoExecAndAsm, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "set", DoSetCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "setmembyte", DoSetMemByte, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "setmemword", DoSetMemWord, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "setreg", DoSetRegister, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "si", DoStepiCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "smb", DoSetMemByte, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "smw", DoSetMemWord, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "sr", DoSetRegister, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "step", DoExecSteps, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "stepi", DoStepiCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "rt", DoRunTraceCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "runtrace", DoRunTraceCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "use", DoUse, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "watch", DoSetWatchCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "x", DoPrintMemCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "xp", DoPrintMemCmd, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  if (Tcl_CreateCommand(interp, "utest", DoUnitTest, NULL, (Tcl_CmdDeleteProc *)NULL) == NULL) return TCL_ERROR;
  
  gInterp = interp;
  fsim_set_prompt();
  getActiveShell()->cmdLinkRegisters();

  // link shell variables
  ActiveThreadName = Tcl_Alloc(32);
  SimFatal((ActiveThreadName), ("Tcl allocation failure"));
  strcpy(ActiveThreadName, VAR_CORE_THREAD_NAME);
  Tcl_LinkVar(interp, VAR_ACTIVE_THREAD_NAME, (char *)&ActiveThreadName, TCL_LINK_STRING);
  
  //fsim_link_str(VAR_ACTIVE_THREAD_NAME, ActiveThreadName, 1);
  fsim_link_int(VAR_VERBOSE_NAME, get_verbose_level_ptr(), 1);
  fsim_link_int(VAR_MULTI_THREAD_NAME, &MultiThreadingMode, 1);

#define INIT_TCL_FILE ".init.tcl"
  // evaluate if a init tcl file exists in current directory
  FILE *fp = fopen (INIT_TCL_FILE, "rb");
  if (fp != NULL) {
    fclose (fp);
    Tcl_Eval(interp, "source "INIT_TCL_FILE);
  }
      
  const char *cmd =  getActiveShell()->cmdGetBatchCmdLine();
  if (cmd && cmd[0]) {
//    printf("commands:[%s]\n", cmd);
    Tcl_Eval(interp, cmd);
  }

  // execute batch file first if specified
  char *cmdFile = getActiveShell()->cmdGetBatchCmdFile();
  if (cmdFile && cmdFile[0]) {
//    printf("Execute batch cmd file:%s\n", cmdFile);
    char cmdBuf[256];
    sprintf(cmdBuf, "source %s", cmdFile);
    Tcl_Eval(interp, cmdBuf);
  }
  
  return getActiveShell()->init();
}

Compare with Previous | Blame | View Log