/************************************************* lxt_recordon - enable recording ************************************************/ int lxt_recordon( int data, int reason ) { acc_initialize(); switch( reason ) { case reason_checktf: if( tf_nump() != 0 ) { tf_error( "too many arguments to recordon" ); tf_dofinish(); } goto DONE; case reason_calltf: if( !lxt.inited ) { tf_error( "recording has not started" ); tf_dofinish(); goto DONE; } break; default: goto DONE; } lxt_enable( 1 ); DONE: acc_close(); return 0; }
/* * routine to setup memory filling routine - set param to 0 on error else 1 * function: $plisetupmemfill(memsiz, memwid) */ static void plisetupmemfil2(int data, int reason) { char *chp; /* get file name as + verilog argument */ if ((chp = mc_scan_plusargs("memfile+")) == NULL || strcmp(chp, "") == 0) { tf_error("missing or empty +memfile+[file name] memory file argument"); tf_putp(0, 0); return; } /* open the file */ if ((memval_s = fopen(chp, "r")) == NULL) { tf_error("unable to open +memfile+ memory file %s", chp); tf_putp(0, 0); return; } /* need memory size for checking */ memsiz = tf_getp(1); memwid = tf_getp(2); if (memwid > 32) { tf_error("for tf_propagatep routine can only use scanf for < 32 bits"); tf_putp(0, 0); return; } tf_putp(0, 1); /* assume memory goes from 1 to size */ last_i = 0; }
/************************************************* lxt2_init - Open lxt file and enable collection ************************************************/ static void lxt2_init() { char* filename; if( lxt.inited ) { tf_error( "recording has alreay begun" ); tf_dofinish(); return; } if( lxt.filename ) { filename = lxt.filename; } else if( lxt.design ) { filename = (char*)malloc( strlen(lxt.design)+4+1 ); if( !filename ) { tf_error( "could not allocate memory" ); tf_dofinish(); return; } sprintf( filename, "%s.lxt", lxt.design ); lxt.filename = filename; } else { char* top = acc_fetch_name( acc_next_topmod(null) ); filename = (char*)malloc( strlen(top)+3+1 ); sprintf( filename, "%s.lxt", top ); lxt.filename = filename; } lxt.t = lxt2_wr_init( filename ); #if DEBUG io_printf( "lxt2_init: %p\n", lxt.t ); #endif if( !lxt.t ) { tf_error( "could not create file '%s'", filename ); tf_dofinish(); return; } lxt2_wr_set_timescale( lxt.t, acc_fetch_precision() ); if( lxt.compress ) { lxt2_wr_set_compression_depth(lxt.t, 9); lxt2_wr_set_partial_off(lxt.t); } else { lxt2_wr_set_compression_depth(lxt.t, 4); lxt2_wr_set_partial_on(lxt.t, 1); } lxt2_wr_set_break_size(lxt.t, lxt.incSize); lxt.inited = 1; lxt.enabled = 1; lxt.updateList = 0; lxt.eventList = 0; lxt.hunk = 0; lxt2_wr_set_initial_value( lxt.t, 'x' ); lxt2_wr_symbol_bracket_stripping( lxt.t, 1 ); lxt2_timemarker(); }
void error_call(int data, int reason) { char *ptr_mipname; char *ptr; int i; int ms, us, ns, ps; get_time (&ms, &us, &ns, &ps); ptr_mipname = tf_mipname(); /* Requires at least two arguments */ if (tf_nump() < ARG2) { tf_error("$error requires at least two arguments, error-disable-tag, and format-string"); tf_dofinish(); return; } /* First argument to $error() must be a string */ if (tf_typep(ARG1) != tf_string) { tf_error("First argument to $error must be a value"); tf_dofinish(); } /* Second argument to $error() must be a string */ if (tf_typep(ARG2) != tf_string) { tf_error("Second argument to $error must be a formating string"); tf_dofinish(); } for (i = 0; i < diserr_num; i++) { ptr = strchr(diserr_arr[i], '.'); if (ptr == NULL) { if (strcmp (tf_getcstringp(ARG1), diserr_arr[i]) == 0) { io_printf ("%05d.%03d.%03d.%03d: ERROR: %s:%s\n", ms,us,ns,ps, ptr_mipname, format(ptr_mipname)); return; } } else { sprintf (format_buffer, "%s.%s\0", tf_getcstringp(ARG1), ptr_mipname); if (strcmp (format_buffer, diserr_arr[i]) == 0) { io_printf ("%05d.%03d.%03d.%03d: ERROR: %s:%s\n", ms,us,ns,ps, ptr_mipname, format(ptr_mipname)); return; } } } io_printf ("%05d.%03d.%03d.%03d: ERROR: %s:%s\n", ms,us,ns,ps, ptr_mipname, format(ptr_mipname)); if (!error_disable) tf_dofinish(); return; }
/* * routine to set memory * function: $pli_memfill(mem[i], i) */ static void plimemfill(int data, int reason) { int i; char memval[1024]; i = tf_getp(2); if (i < 0 || i > memsiz) { tf_error("cannot fill memory location %d - memory has only %d cells"); tf_putp(0, 0); return; } if (fscanf(memval_s, "%s", memval) != 1) { /* problably should access OS error name here */ tf_error("error reading memory value for cell %d", i); tf_putp(0, 0); return; } /* probably should add code to check for memval as legal binary number */ /* but can be any width since putp assignment will widen or truncate */ /* make sure index i is legal - since must have used i in memory select */ /* only for checking */ if (i != last_i + 1) { tf_error("memory index %d non in sequence - %d expected", i, last_i + 1); tf_putp(0, 0); return; } last_i = i; /* this is #0, in CVC you would use extension routine tf_strputp */ /* it is identical to tf_strdelputp except string assignment immediate */ #ifdef __HAS_STRPUTP__ /* notice need final delay type parameter since may need to cancel */ /* events if delay form used elsewhere */ printf("*** using tf_strputp\n"); if (tf_strputp(1, memwid, 'b', memval) == 0) #else if (tf_strdelputp(1, memwid, 'b', memval, 0, 0) == 0) #endif { tf_error("strdelput of index memory failed"); tf_putp(0, 0); return; } tf_putp(0, 1); }
/* * check the fill memory user PLI function * notice calling tf_error here will inhibit simulation * probably sould also check 2nd index argument */ static void check_plimemfil2(int data, int reason) { if (tf_nump() != 2) { tf_error("$pli_memfil2 has %d arguments - 2 required", tf_nump()); return; } /* this associates nodeinfo struct with argument */ tf_nodeinfo(1, &ninfo); if (ninfo.node_type != TF_MEMORY_NODE) { tf_error("$pli_memfil2 first argument not read/write memory select"); return; } }
/************************************************* lxt2_option - set a option ************************************************/ static void lxt2_option( char* str ) { char* eq = index( str, '=' ); int len = strlen( str ); if( eq ) { len -= strlen( eq ); } else if( !strncmp( str, "incsize", len ) ) { lxt.incSize = atoi( eq+1 ); } else if( !strncmp( str, "speed", len ) ) { lxt.compress = 0; } else if( !strncmp( str, "space", len ) ) { lxt.compress = 1; } else if( !strncmp( str, "sequence", len ) ) { lxt.sequence = 1; } else if( !strncmp( str, "nosequence", len ) ) { lxt.sequence = 0; } else if( !strncmp( str, "design", len ) ) { lxt.design = strdup( eq+1 ); } else if( !strncmp( str, "depth", len ) ) { lxt.depth = atoi( eq+1 ); } else { tf_error( "option %s not supported", str ); tf_dofinish(); } }
/* * check the fill memory user PLI function * notice calling tf_error here will inhibit simulation * probably sould also check 2nd index argument */ static void check_plimemfill(int data, int reason) { struct t_tfexprinfo xinfo; if (tf_nump() != 2) { tf_error("$pli_memfill has %d arguments - 2 required", tf_nump()); return; } tf_exprinfo(1, &xinfo); if (xinfo.expr_type != TF_RWMEMSELECT) { tf_error("$pli_memfill first argument not read/write memory select"); return; } }
void genDumpMod_call(int data, int reason) { handle child_handle, module_handle; char *pargs, *ptr, *mod_name; int pargs_found, level; char buf[128]; pargs = mc_scan_plusargs ("gen_dump_module="); pargs_found = 0; if (pargs != (char *)0) { strcpy(buf, pargs); mod_name = strtok (buf, ":"); ptr = strtok (NULL, " \n"); level = atoi (ptr); if (level > 0 ) {pargs_found = 1;} } if (pargs_found == 0) return; io_printf ("%s %d\n", mod_name, level); if ((fp = fopen("dump.mod", "w")) == 0) tf_error ("can't open dump.mod file\n"); acc_initialize(); module_handle = acc_handle_object (mod_name); child_handle = null; next_level (module_handle, level); acc_close(); fclose (fp); tf_dofinish(); }
/* * routine to set memory using tf_propagatep method * * must be 32 bits or less otherwise would need to write vecval manipulation * routines * * function: $pli_memfil2(mem[i], i) * here tfputp would be better choice since only allows non x/z forms */ static void plimemfil2(int data, int reason) { int i; unsigned memval; struct t_vecval *vecp; i = tf_getp(2); if (i < 0 || i > memsiz) { tf_error("cannot fill memory location %d - memory has only %d cells"); tf_putp(0, 0); return; } if (fscanf(memval_s, "%u", &memval) != 1) { /* problably should access OS error name here */ tf_error("error reading memory value for cell %d", i); tf_putp(0, 0); return; } /* probably should add code to check for memval as legal binary number */ /* but can be any width since putp assignment will widen or truncate */ /* make sure index i is legal - since must have used i in memory select */ /* only for checking */ if (i != last_i + 1) { tf_error("memory index %d non in sequence - %d expected", i, last_i + 1); tf_putp(0, 0); return; } last_i = i; tf_exprinfo(1, &xinfo); /* set value - using 32 bit value else would need string to 0*/ vecp = xinfo.expr_value_p; vecp[0].avalbits = (int) memval; vecp[0].bvalbits = 0; /* do assign - notice this forces re-evaluate of argument during assign */ /* SJM 12/20/02 - following LRM, fail is 1 not 0 */ if (tf_propagatep(1) == 1) { tf_error("tf_propagatep of indexed memory failed"); tf_putp(0, 0); } else tf_putp(0, 1); }
void info_call(int data, int reason) { char *ptr_mipname; int i, level; int ms, us, ns, ps; get_time (&ms, &us, &ns, &ps); ptr_mipname = tf_mipname(); /* Requires at least two arguments */ if (tf_nump() < ARG2) { tf_error("$info requires at least two arguments, info-level and format-string"); tf_dofinish(); return; } /* First argument to $info() must be a value */ if (tf_typep(ARG1) != tf_readonly) { tf_error("First argument to $info must be a value"); tf_dofinish(); } /* Second argument to $info() must be a string */ if (tf_typep(ARG2) != tf_string) { tf_error("Second argument to $info must be a formating string"); tf_dofinish(); } level = tf_getp(ARG1); if (level == 0) { io_printf ("%05d.%03d.%03d.%03d: INFO(%d): %s:%s\n", ms,us,ns,ps, level, ptr_mipname, format(ptr_mipname)); } else { for (i = 0; i < mon_path_num; i++) { if ((level <= mon_level[i]) && (strmatch (mon_inst_path[i], ptr_mipname) == 0) ) { io_printf ("%05d.%03d.%03d.%03d: INFO(%d): %s:%s\n", ms,us,ns,ps, level, ptr_mipname, format(ptr_mipname)); } } } return; }
int fseq_checktf() { int err = 0; if (tf_nump() != 1) { tf_error("$fibonacci requires exactly 1 argument.\n"); err = 1; } if (tf_typep(1) == tf_nullparam) { tf_error("$fibonacci cannot have a NULL argument.\n"); err = 1; } if (tf_sizep(1) > 8) { tf_error("$fibonacci input no larger than 8-bits.\n"); err = 1; } if (err) { tf_message(ERR_ERROR, "", "", ""); } return(0); }
void warn_call(int data, int reason) { char *ptr_mipname; int i; int ms, us, ns, ps; get_time (&ms, &us, &ns, &ps); ptr_mipname = tf_mipname(); /* Requires at least two arguments */ if (tf_nump() < ARG2) { tf_error("$warn requires at least two arguments, warn-disable-tag, and format-string"); tf_dofinish(); return; } /* First argument to $warn() must be a string */ if (tf_typep(ARG1) != tf_string) { tf_error("First argument to $warn must be a value"); tf_dofinish(); } /* Second argument to $warn() must be a string */ if (tf_typep(ARG2) != tf_string) { tf_error("Second argument to $warn must be a formating string"); tf_dofinish(); } for (i = 0; i < diswarn_num; i++) { if (strcmp (tf_getcstringp(ARG1), diswarn_arr[i]) == 0) return; } io_printf ("%05d.%03d.%03d.%03d: WARN: %s:%s\n", ms,us,ns,ps, ptr_mipname, format(ptr_mipname)); return; }
int util_get_plus_args_str() { /* Example use: invocation script (bosox is passed in as first argument) ----------------- set basename = $1 verilog mymodule.v +tst_file_name${basename}.tst +log_file_name${basename}.log +err_file_name${basename}.err +result_file_name${basename}.result mymodule.v ---------- reg [32*8:1] tst_file_name; // plus argument string value reg [32*8:1] err_file_name; // plus argument string value reg [32*8:1] log_file_name; // plus argument string value reg [32*8:1] result_file_name; // plus argument string value integer plus_arg_ok; // 0 if ok, 1 if no plus argument value initial begin // get strings from plus argument values plus_arg_ok = $util_get_plus_args_str("tst_file_name", tst_file_name); plus_arg_ok = $util_get_plus_args_str("err_file_name", err_file_name); plus_arg_ok = $util_get_plus_args_str("log_file_name", log_file_name); plus_arg_ok = $util_get_plus_args_str("result_file_name",result_file_name); $display("tst_file_name is %s", tst_file_name); $display("err_file_name is %s", err_file_name); $display("log_file_name is %s", log_file_name); $display("result_file_name is %s", result_file_name); end */ /* Input is string Returning value is string. */ handle wrk_out; char *strArgIn; int sizeOut,sizeS_in; int numArgs; int cnt,size; char *buffer, *bufferout; s_setval_value value_out; s_setval_delay delay_out; delay_out.model = accNoDelay; delay_out.time.type = accRealTime; delay_out.time.real = 0.0; value_out.format = accHexStrVal; acc_initialize(); numArgs = tf_nump(); if(numArgs !=2) { tf_error("$get_plus_arg_string must have two arguments"); tf_putp(0,VERILOG_ERROR); return(VERILOG_ERROR); } /* Fetch the input register and size */ wrk_out = acc_handle_tfarg(2); sizeOut = (acc_fetch_size(wrk_out)/8); /* Get the string value */ strArgIn = mc_scan_plusargs(tf_getcstringp(1)); if (strArgIn == NULL) { if (DEBUG_PLUS_ARGS) io_printf("get_plus_args_str(): Matching string is not found: %s.\n", tf_getcstringp(1)); tf_putp(0,VERILOG_ERROR); return(VERILOG_ERROR); } if (strArgIn) { if (DEBUG_PLUS_ARGS) io_printf("get_plus_args_str(): Got string value: %s\n",strArgIn); } else { io_printf("get_plus_args_str(): Bad input string value.\n"); tf_putp(0,VERILOG_ERROR); return(VERILOG_ERROR); } /* Build new string */ sizeS_in = strlen(strArgIn); bufferout = (char *) malloc(sizeS_in + 1); sprintf(bufferout, "%s",strArgIn); if (sizeOut < sizeS_in) { tf_error("get_plus_args_str(): Register %s is not large enough.\n", acc_fetch_fullname(wrk_out)); tf_putp(0,VERILOG_ERROR); return(VERILOG_ERROR); } size = sizeS_in*2; buffer = (char *) malloc(size + 1); for (cnt =0; cnt < size; cnt +=2){ if (cnt < size){ /* Convert string into HEX code */ sprintf(&buffer[cnt],"%x",bufferout[cnt/2]); } } /* Null out the rest of the register else { buffer[cnt] = '\0'; buffer[cnt +1] = '\0'; } */ /* assign buffer to the verilog register */ value_out.value.str = buffer; acc_set_value(wrk_out, &value_out, &delay_out); tf_putp(0,VERILOG_OK); acc_close(); free(buffer); free(bufferout); return(VERILOG_OK); }
/************************************************* lxt_incinit - close current file and open a new one maintaining the same trace info ************************************************/ static void lxt_incinit() { char* filename; char* dot; info_p info; #if DEBUG io_printf( "lxt_incinit: %p\n", lxt.t ); #endif /* * pinch off old file */ lxt_timemarker(); lt_close( lxt.t ); /* * create new filename */ lxt.hunk++; filename = (char*)malloc( strlen(lxt.filename)+10+1 ); dot = rindex( lxt.filename, '.' ); *dot = 0; if( lxt.hunk > 1 ) { dot = rindex( lxt.filename, '-' ); *dot = 0; } sprintf( filename, "%s-%d.lxt", lxt.filename, lxt.hunk ); free( lxt.filename ); lxt.filename = filename; /* * open new wave file */ lxt.t = lt_init( filename ); if( !lxt.t ) { tf_error( "could not create file '%s'", filename ); tf_dofinish(); return; } lt_set_clock_compress( lxt.t ); if( lxt.compress ) { // lt_set_chg_compress( lxt.t ); } lxt.updateList = 0; lxt.eventList = 0; lt_set_initial_value( lxt.t, 'x' ); lt_symbol_bracket_stripping( lxt.t, 1 ); lt_set_timescale( lxt.t, acc_fetch_precision() ); lxt_timemarker(); /* * add existing objects to new file */ info = lxt.objectList; while( info ) { int flags; int msb; int lsb; if( info->real ) { flags = LT_SYM_F_DOUBLE; } else { flags = LT_SYM_F_BITS; } if( info->real ) { info->symbol = lt_symbol_add( lxt.t, info->name, 0, 0, 0, flags ); } else if( info->event ) { info->symbol = lt_symbol_add( lxt.t, info->name, 0, 0, 0, flags ); } else { acc_fetch_range( info->object, &msb, &lsb ); info->symbol = lt_symbol_add( lxt.t, info->name, 0, msb, lsb, flags ); } info = info->next; } if( lxt.compress ) { lt_set_no_interlace( lxt.t ); } lxt_dump( lxt.objectList, 1 ); }
static void socket_read_regs_all_error (int err) { tf_error ("socket-pli: incomplete regs value (from read-regs-all call (%d))\n", err); tf_dofinish(); }
/************************************************* lxt2_add - add object to file ************************************************/ static void lxt2_add( handle object, int depth ) { int real = 0; int event = 0; int flags; int msb; int lsb; info_p info; handle block; handle term; static int filter[] = { accIntegerVar, accNamedEvent, accNet, accRealVar, accRegister, accTimeVar, 0 }; switch( acc_fetch_type(object) ) { case accNamedEvent: flags = LXT2_WR_SYM_F_BITS; event = 1; break; case accRealVar: flags = LXT2_WR_SYM_F_DOUBLE; real = 1; break; case accIntegerVar: case accNet: case accPort: case accReg: case accTimeVar: case accParameter: flags = LXT2_WR_SYM_F_BITS; break; case accStatement: case accTask: case accModule: term = null; while(1) { term = acc_next( filter, object, term ); if( term == null ) { break; } lxt2_add( term, depth ); } if( depth == 1 ) { return; } block = null; while(1) { block = acc_next_child( object, block ); if( block == null ) { break; } lxt2_add( block, (depth==0) ? 0 : depth-1 ); } return; default: return; } info = (info_p)malloc( sizeof(info_t) ); if( !info ) { tf_error( "cannot allocate memory" ); tf_dofinish(); return; } info->object = object; info->name = strdup( acc_fetch_fullname(object) ); info->next = lxt.objectList; lxt.objectList = info; info->sequence = lxt.sequence; info->event = event; info->real = real; info->updateNext = 0; if( real ) { info->symbol = lxt2_wr_symbol_add( lxt.t, info->name, 0, 0, 0, flags ); } else if( event ) { info->symbol = lxt2_wr_symbol_add( lxt.t, info->name, 0, 0, 0, flags ); } else { acc_fetch_range( object, &msb, &lsb ); #if DEBUG io_printf( "lxt2_add: %s [ %d : %d ]\n", info->name, msb, lsb ); #endif info->symbol = lxt2_wr_symbol_add( lxt.t, info->name, 0, msb, lsb, flags ); } acc_vcl_add( object, lxt2_changed, (char*)info, vcl_verilog_logic ); #if DEBUG io_printf( "lxt2_recordvars: adding %p %s\n", info->symbol, info->name ); #endif }
void monInit_check(int data, int reason) { int i; char *string, *name, *ptr, ch; if (monInit_done) return ; monInit_done = 1 ; /* * plus args for info. * +mon0=cpu0:25 +mon1=ccx:35 */ mon_path_num = 0; while (1) { sprintf (mon_name_buf, "mon%d=\0", mon_path_num); string = mc_scan_plusargs(mon_name_buf); if (string != 0) { strcpy(mon_name_buf, string); ptr = strtok (mon_name_buf, ":"); if (ptr == 0) { tf_error("Syntax error in mon%i plus arg (instance path)\n", mon_path_num); tf_dofinish(); return; } mon_inst_path[mon_path_num] = strdup (ptr); ptr = strtok (NULL, ":"); if (ptr == 0) { tf_error("Syntax error in mon%i plus arg (level)\n", mon_path_num); tf_dofinish(); return; } mon_level[mon_path_num] = atoi (ptr); } else { break; } mon_path_num++; } /* * plus args for diserr. * +diserr=uce:cer:xyz */ diserr_num = 0; string = mc_scan_plusargs("diserr="); if (string != 0) { ptr = strtok (string, ":"); if (ptr == 0) { tf_error("Syntax error in diserr plus arg\n"); tf_dofinish(); return; } while (1) { diserr_arr[diserr_num] = strdup (ptr); diserr_num++; ptr = strtok (NULL, ":"); if (ptr == 0) break; } } /* * plus args for diswarn. * +diswarn=mem0:mem3 */ diswarn_num = 0; string = mc_scan_plusargs("diswarn="); if (string != 0) { ptr = strtok (string, ":"); if (ptr == 0) { tf_error("Syntax error in diswarn plus arg\n"); tf_dofinish(); return; } while (1) { diswarn_arr[diswarn_num] = strdup (ptr); diswarn_num++; ptr = strtok (NULL, ":"); if (ptr == 0) break; } } }
/************************************************* lxt2_recordvars - add objects to be recorded ************************************************/ int lxt2_recordvars( int data, int reason ) { int update = 0; int objects = 0; int i; acc_initialize(); switch( reason ) { case reason_calltf: break; case reason_checktf: goto DONE; case reason_finish: if( lxt.inited ) { lxt2_close(); } goto DONE; case reason_rosynch: update = (lxt.updateList != NULL); while( lxt.updateList ) { info_p info; info = lxt.updateList; lxt2_dump( info, 0 ); lxt.updateList = info->updateNext; info->updateNext = 0; } if( update ) { lxt2_timemarkerp1(); } while( lxt.eventList ) { info_p info; info = lxt.eventList; lxt2_dump( info, 1 ); lxt.eventList = info->updateNext; info->updateNext = 0; } lxt2_nexttimemarker(); goto DONE; default: goto DONE; } ginstance = tf_getinstance(); /* * parse options first */ for( i = 1; i <= tf_nump(); ++i ) { handle object; if( tf_typep(i) == tf_nullparam ) { continue; } if( tf_typep(i) == tf_string ) { char* str = acc_fetch_tfarg_str(i); lxt2_option( str ); continue; } } /* * on first call, initialize structure */ if( !lxt.inited ) { lxt2_init(); } for( i = 1; i <= tf_nump(); ++i ) { handle object; if( tf_typep(i) == tf_nullparam ) { continue; } if( tf_typep(i) == tf_string ) { continue; } object = acc_handle_tfarg(i); if( !object ) { tf_error( "cannot find object" ); tf_dofinish(); goto DONE; } lxt2_add( object, lxt.depth ); objects++; } if( objects == 0 ) { #if DEBUG io_printf( "lxt2_recordvars: defaultpath=%s\n", acc_fetch_fullname(acc_handle_parent(acc_handle_tfinst())), lxt.depth ); #endif lxt2_add( acc_handle_parent(acc_handle_tfinst()), lxt.depth ); } lxt2_dump( lxt.objectList, 1 ); DONE: acc_close(); return 0; }