blob: 9ee476040460b49ab64119d8b1d62226eeff8c20 [file] [log] [blame]
/*
** -------------------------------------------------------------
** Copyright 2004-2008 Synopsys, Inc.
** All Rights Reserved Worldwide
**
** Licensed under the Apache License, Version 2.0 (the
** "License"); you may not use this file except in
** compliance with the License. You may obtain a copy of
** the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in
** writing, software distributed under the License is
** distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
** CONDITIONS OF ANY KIND, either express or implied. See
** the License for the specific language governing
** permissions and limitations under the License.
** -------------------------------------------------------------
*/
#include "tcl.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <malloc.h>
#include "vcsuser.h"
#ifndef TESTING
#include "svdpi.h"
#endif
/* user defined types */
/* basic type which will be passed to Verilog,
* maps to the xvc_parse_cmd class in xvc_manager
*/
typedef struct xvc_parse_cmd {
int argc;
char **argv; /* arg list */
char *testfile; /* source file */
char *linec; /* line no.*/
char *err_msg; /* error msg seen in parsing */
struct xvc_parse_cmd *next;
} xvc_parse_cmd_t;
/*List of xvc_cmds and associated functions to maintain list*/
/* Note: need this right now, as DPI export functions to dynamic
* types are not yet supported. Hence, need to keep the complete
* set of commands in a list, and at the end of processing
* iterate over the list elements one-by-one
*/
xvc_parse_cmd_t *xvc_cmd_list;
xvc_parse_cmd_t *xvc_current_cmd_read_p; /* read pointer */
xvc_parse_cmd_t *xvc_current_cmd_p;
char *xvc_current_err_msg;
/* Globals */
Tcl_Interp *xvc_tcl_interp;
/* Prototypes and functions */
int xvc_put_cmd_args(
ClientData clientData,
Tcl_Interp *interp,
int argc,
char *argv[]) ;
int xvc_error_handler(
ClientData clientData,
Tcl_Interp *interp,
int argc,
char *argv[]) ;
void xvc_register_tcl_functions () ;
int xvc_tcl_init () ;
xvc_parse_cmd_t *xvc_cmd_copy(xvc_parse_cmd_t xvc_cmd) ;
void xvc_cmd_free(xvc_parse_cmd_t *xvc_cmd) ;
void xvc_cmd_free_all() ;
void xvc_add_item(xvc_parse_cmd_t *xvc_cmd) ;
void xvc_cmd_print(xvc_parse_cmd_t *cmd) ;
xvc_parse_cmd_t *xvc_get_cmd() ;
int vmm_xvc_get_next_cmd(int *argc_p,
char **argv,
char **testfile_p,
char **linec_p,
char **err_msg_p) ;
/* Functions to manipulate xvc_cmd_list */
xvc_parse_cmd_t *xvc_cmd_copy(xvc_parse_cmd_t xvc_cmd) {
int i;
xvc_parse_cmd_t *item;
item = (xvc_parse_cmd_t *) malloc (sizeof(xvc_parse_cmd_t));
item->argc = xvc_cmd.argc;
item->testfile = strdup(xvc_cmd.testfile);
item->linec = strdup(xvc_cmd.linec);
item->argv = (char **) malloc(sizeof(char **)*(item->argc));
for (i = 0; i < item->argc; i++) {
/* ignore the first ie., "put_cmd_args" */
item->argv[i] = strdup(xvc_cmd.argv[i]);
}
item->next = xvc_cmd.next;
return (item);
}
/* frees up the internals of xvc_cmd, and xvc_cmd itself */
void xvc_cmd_free(xvc_parse_cmd_t *xvc_cmd) {
int i;
if (xvc_cmd == NULL)
return;
free(xvc_cmd->testfile);
free(xvc_cmd->linec);
for (i = 0; i < xvc_cmd->argc; i++) {
free(xvc_cmd->argv[i]);
}
free(xvc_cmd->argv);
if (xvc_cmd->err_msg)
free(xvc_cmd->err_msg);
free(xvc_cmd);
}
/* adds to end of the global linked list */
void xvc_add_item(xvc_parse_cmd_t *xvc_cmd) {
xvc_parse_cmd_t *tmp;
xvc_cmd->next = NULL;
if (xvc_cmd_list == NULL) {
xvc_cmd_list = xvc_cmd;
xvc_current_cmd_read_p = xvc_cmd_list; /* init the read pointer */
} else {
/* walk along list to the end */
for (tmp = xvc_cmd_list;
tmp->next != NULL;
tmp = tmp->next);
tmp->next = xvc_cmd;
}
}
/* print */
void xvc_cmd_print(xvc_parse_cmd_t *cmd) {
int i;
io_printf("-------DPI: %s[%s] -------\n",
cmd->testfile,
cmd->linec);
for (i = 0; i < cmd->argc; i++) {
io_printf(" %s\n", cmd->argv[i]);
}
if (cmd->err_msg)
io_printf(" %s\n", cmd->err_msg);
}
/* gets from the current read ptr of the list */
/* note, it is the caller's responsibility to free up the
* returned cmd after work on it is done
*/
xvc_parse_cmd_t *xvc_get_cmd() {
xvc_parse_cmd_t *retval;
if (xvc_cmd_list) {
retval = xvc_current_cmd_read_p;
if (xvc_current_cmd_read_p)
xvc_current_cmd_read_p = xvc_current_cmd_read_p->next;
} else {
retval = NULL;
}
return(retval);
}
/* delete the entire list */
void xvc_cmd_free_all() {
xvc_parse_cmd_t *item;
while (xvc_cmd_list != NULL) {
item = xvc_cmd_list->next;
xvc_cmd_free(xvc_cmd_list);
xvc_cmd_list = item;
}
xvc_current_cmd_read_p = NULL; /* reset read pointer also */
}
/* on being called, send the current head of the list to the
* Verilog side. The list head also gets moved
* Since the verilog side makes a copy, this function also
* frees up memory of the current command when done
* Returns 1 if valid entry, 0 if empty, or some other error
*/
int vmm_xvc_get_next_cmd(int *argc_p,
char **argv,
char **testfile_p,
char **linec_p,
char **err_msg_p) {
int i;
xvc_parse_cmd_t *item;
if ((item = xvc_get_cmd()) == NULL)
return (0);
*argc_p = item->argc;
*testfile_p = item->testfile;
*linec_p = item->linec;
*err_msg_p = item->err_msg;
for (i = 0; i < item->argc; i++) {
argv[i] = item->argv[i];
}
return(1);
}
/* initialize TCL interpreter
* Standard initialization and other init tasks, such
* as registering any TCL commands.
* Return TCL_OK on success, TCL_ERROR on failure
*/
int xvc_tcl_init () {
if ((xvc_tcl_interp = Tcl_CreateInterp()) == NULL)
return (TCL_ERROR);
return (TCL_OK);
}
void xvc_register_tcl_functions () {
/* register user TCL functions */
Tcl_CreateCommand(xvc_tcl_interp,
"put_cmd_args",
(void *) xvc_put_cmd_args,
(ClientData) NULL,
(Tcl_CmdDeleteProc *) NULL);
/* register user TCL functions */
Tcl_CreateCommand(xvc_tcl_interp,
"xvc_error_handler",
(void *) xvc_error_handler,
(ClientData) NULL,
(Tcl_CmdDeleteProc *) NULL);
}
/* error handling...
* Argument is the error_msg
* Append the err_msg to the error string of the current cmd
***/
int xvc_error_handler(
ClientData clientData,
Tcl_Interp *interp,
int argc,
char *argv[]) {
if (argc != 2)
io_printf("xvc_manager: Unknown error !!\n");
#ifdef DEBUG_DPI
io_printf("Error_C: %s\n",argv[1]);
#endif
/* append to xvc_current_err_msg */
if (xvc_current_err_msg == NULL)
xvc_current_err_msg = strdup(argv[1]);
return (TCL_OK);
}
/* C functions registered with TCL
* Gets the arglist, file, linec and error msg in a command
* The last two args are
* - file
* - linec
* The args before this are the cmd line args.
*/
int xvc_put_cmd_args(
ClientData clientData,
Tcl_Interp *interp,
int argc,
char *argv[]) {
int i;
xvc_current_cmd_p = (xvc_parse_cmd_t *) malloc (sizeof(xvc_parse_cmd_t));
/* assign new data */
xvc_current_cmd_p->argc = argc - 3;
xvc_current_cmd_p->testfile = strdup(argv[argc-2]);
xvc_current_cmd_p->linec = strdup(argv[argc-1]);
xvc_current_cmd_p->argv = (char **)
malloc(sizeof(char **)*(xvc_current_cmd_p->argc));
for (i = 0; i < xvc_current_cmd_p->argc; i++) {
/* ignore the first ie., "put_cmd_args" */
xvc_current_cmd_p->argv[i] = strdup(argv[i+1]);
}
/* put the current error msg into this cmd */
xvc_current_cmd_p->err_msg = xvc_current_err_msg;
/* put onto the linked list tail of commands */
xvc_add_item(xvc_current_cmd_p);
#ifdef DEBUG_DPI
xvc_cmd_print(xvc_current_cmd_p);
#endif
return TCL_OK;
}
void
vmm_xvc_tcl_execute_file(char *test_file) {
int tcl_error;
char xvc_home_path[200];
char *xvc_tcl_utils_file_fullpath;
char xvc_tcl_cmd_buf[1000];
/* perform creation and inits of the TCL interpreter */
tcl_error = xvc_tcl_init();
if (tcl_error != TCL_OK) {
io_printf("Error in initialization of TCL for VMM xvc manager\n");
abort();
}
/* Source the startup script */
/* Check for +vmm_path=%s string, if present, it overrides
VCS_HOME/etc/vmm as the location to pickup the vmm_xvc_parse.tcl
initialization file */
if (mc_scan_plusargs("vmm_path")) {
char *str;
str = mc_scan_plusargs("vmm_path") + 1;
strcpy(xvc_home_path,str);
strcat(xvc_home_path,"/");
} else {
/* get VCS_HOME env. variable */
char *vcs_home_path;
vcs_home_path = getenv("VCS_HOME");
if (vcs_home_path == NULL) {
io_printf("VCS_HOME env. variable not set, needed for xvc manager\n");
abort();
}
strcpy(xvc_home_path,vcs_home_path);
strcat(xvc_home_path,"/etc/vmm/");
}
/* ToDo: Error out if xvc_home_path is NULL */
xvc_tcl_utils_file_fullpath = strcat(xvc_home_path, "vmm_xvc_parse.tcl");
tcl_error = Tcl_EvalFile(xvc_tcl_interp, xvc_tcl_utils_file_fullpath);
if (tcl_error != TCL_OK) {
io_printf("Error: xvc manager: could not eval file %s\n",xvc_tcl_utils_file_fullpath);
io_printf(" Either +vmm_path=<str> or VCS_HOME env. variable needs to be provided\n");
abort();
}
/* register user TCL functions */
xvc_register_tcl_functions();
/* execute the parse-start command from C */
sprintf(xvc_tcl_cmd_buf, "execute_file %s", test_file);
tcl_error = Tcl_Eval(xvc_tcl_interp, xvc_tcl_cmd_buf);
if (tcl_error != TCL_OK) {
io_printf("Error: xvc manager: in executing file %s: File does not exist ?\n",
test_file);
abort();
}
}
#ifdef TESTING
int main() {
vmm_xvc_tcl_execute_file("./TESTFILES/test.txt");
/* print out the list of commands */
/* iterate over the cmd list, and print them out one by one */
{
xvc_parse_cmd_t *item;
while ((item = xvc_get_cmd())) {
xvc_cmd_print(item);
}
xvc_cmd_free_all();
}
}
#endif