static PLI_INT32 size_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv; vpiHandle arg; (void)name; /* Parameter is not used. */ argv = vpi_iterate(vpiArgument, callh); assert(argv); arg = vpi_scan(argv); assert(arg); vpi_free_object(argv); int res = vpi_get(vpiSize, arg); s_vpi_value value; value.format = vpiIntVal; value.value.integer = res; vpi_put_value(callh, &value, 0, vpiNoDelay); return 0; }
static PLI_INT32 sys_fopenrwa_calltf(PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); s_vpi_value val; char *mode, *fname; errno = 0; /* Get the mode. */ mode = name + strlen(name) - 1; /* Get the file name. */ fname = get_filename(callh, name, vpi_scan(argv)); vpi_free_object(argv); if (fname == 0) return 0; /* Open the file and return the result. */ val.format = vpiIntVal; val.value.integer = vpi_fopen(fname, mode); vpi_put_value(callh, &val, 0, vpiNoDelay); free(fname); return 0; }
static PLI_INT32 sys_mti_dist_uniform_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle callh, argv, seed, start, end; s_vpi_value val; long i_seed, i_start, i_end; (void)name; /* Parameter is not used. */ /* Get the argument handles and convert them. */ callh = vpi_handle(vpiSysTfCall, 0); argv = vpi_iterate(vpiArgument, callh); seed = vpi_scan(argv); start = vpi_scan(argv); end = vpi_scan(argv); val.format = vpiIntVal; vpi_get_value(seed, &val); i_seed = val.value.integer; vpi_get_value(start, &val); i_start = val.value.integer; vpi_get_value(end, &val); i_end = val.value.integer; /* Calculate and return the result. */ val.value.integer = mti_dist_uniform(&i_seed, i_start, i_end); vpi_put_value(callh, &val, 0, vpiNoDelay); /* Return the seed. */ val.value.integer = i_seed; vpi_put_value(seed, &val, 0, vpiNoDelay); vpi_free_object(argv); return 0; }
PLI_INT32 CompileTF(PLI_BYTE8 *user_data) #endif { s_cb_data cb_data; vpiHandle call_h=vpi_handle(vpiSysTfCall,NULL); vpiHandle arg_i,arg_h; (void)user_data; /* Parameter is not used. */ // Get First Argument and Setup Value Change Callback arg_i=vpi_iterate(vpiArgument,call_h); arg_h=vpi_scan(arg_i); vpi_free_object(arg_i); cb_data.reason = cbValueChange; cb_data.cb_rtn = ValueChange; cb_data.value = NULL; cb_data.time = NULL; cb_data.user_data = NULL; cb_data.obj = arg_h; vpi_register_cb(&cb_data); return(0); }
PLI_INT32 cmt_init_comp(PLI_BYTE8 * user_data) { (void) user_data; vpiHandle systf_handle, arg_handle, arg_iter = NULL; PLI_INT32 arg_type; bool err = false; systf_handle = vpi_handle(vpiSysTfCall, NULL); arg_iter = vpi_iterate(vpiArgument, systf_handle); if (arg_iter == NULL) { vpi_printf("ERROR: $cmt_init takes exactly 2 arguments\n"); err = true; goto INIT_COMP_FINISH; } //scan for first argument arg_handle = vpi_scan(arg_iter); arg_type = vpi_get(vpiType, arg_handle); if ( (arg_type != vpiConstant) && (arg_type != vpiIntegerVar) && (arg_type != vpiParameter) ) { vpi_printf("first argument to $cmt_init should be an integer specifying the maximum width of the cmt circuit.\n"); err = true; goto INIT_COMP_FINISH; } //scan for second arguement arg_handle = vpi_scan(arg_iter); if (arg_handle == NULL) { arg_iter = NULL; // according to the standard, once vpi_scan returns NULL, the iterator is freed vpi_printf("ERROR: $cmt_init takes exactly 2 arguments\n"); err = true; goto INIT_COMP_FINISH; } arg_type = vpi_get(vpiType, arg_handle); if ( (arg_type != vpiConstant) && (arg_type != vpiIntegerVar) && (arg_type != vpiParameter) ) { vpi_printf("ERROR: Second argument to $cmt_init should be an integer specifying the depth of the cmt cricuit.\n"); err = true; goto INIT_COMP_FINISH; } if (vpi_scan(arg_iter) != NULL) { vpi_printf("ERROR: $cmt_init takes exactly 2 arguments"); err = true; goto INIT_COMP_FINISH; } else { // vpi_scan(arg_iter) returned NULL, so arg_iter was automatically freed arg_iter = NULL; } INIT_COMP_FINISH: // free the iterator unless it's already been freed if ( (arg_iter != NULL) && (vpi_scan(arg_iter) != NULL) ) { vpi_free_object(arg_iter); } if (err) { vpi_control(vpiFinish, 1); } return 0; }
/* * Check that the given $table_model() call has valid arguments. */ static PLI_INT32 sys_table_model_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle arg; p_table_mod table = create_table(); /* See if there are any table model arguments. */ check_command_line_flags(); /* Check that there are arguments. */ if (argv == 0) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s requires at least two arguments.\n", name); vpi_control(vpiFinish, 1); return 0; } /* The first N (dimensions) arguments must be numeric. */ for (arg = vpi_scan(argv); arg && is_numeric_obj(arg); arg = vpi_scan(argv)) { table->dims += 1; table->indep = (vpiHandle *)realloc(table->indep, sizeof(vpiHandle)*table->dims); table->indep[table->dims-1] = arg; } /* We must have a data file. */ if (arg == 0) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s requires a file name argument.\n", name); vpi_control(vpiFinish, 1); return 0; } /* For now we only allow a constant string (file name). */ if (! is_const_string_obj(arg)) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s file name argument must be a constant string.\n", name); vpi_control(vpiFinish, 1); return 0; } table->file.arg = arg; /* There may be an optional constant string (control string). */ arg = vpi_scan(argv); if (arg) { if (! is_const_string_obj(arg)) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s control string argument must be a constant " "string.\n", name); vpi_control(vpiFinish, 1); return 0; } check_for_extra_args(argv, callh, name, "N numeric and 1 or 2 " " constant string arguments", 0); table->control.arg = arg; } /* Save the table data information. */ vpi_put_userdata(callh, table); return 0; }
static PLI_INT32 xxx_calltf(PLI_BYTE8 *user_data) #endif { vpiHandle systf_h; s_vpi_value vpival; /* get/set register values */ s_vpi_time t; vpiHandle arg_iterator; int i; vpiHandle argi[100]; (void)user_data; /* Parameter is not used. */ /* Get handle to this instance, look up our workarea */ systf_h = vpi_handle(vpiSysTfCall, NULL); chkvpierr(); arg_iterator = vpi_iterate(vpiArgument, systf_h); chkvpierr(); i = 0; if (arg_iterator == NULL) { fprintf(stderr, "ERROR: missing argument list to $example(...)"); } /* Copy args pointers into argi array */ while ((argi[i] = vpi_scan(arg_iterator)) != NULL) { chkvpierr(); i++; } /* iterator is exhausted, no need to free */ /* Fill in the time struct */ t.type = vpiScaledRealTime; t.high = 0; t.low = 0; t.real = 10.0; /* Fill in the value struct */ vpival.format = vpiBinStrVal; vpival.value.str = charbuf; /* * This is where the real work happens. We are called in an intial * block and we schedule three "set-values" at times 10, 20 and 30 * to args 0, 1 and 2. The charbuf gets shared among the three * calls, even though it shouldn't and the values are not distinct. */ /* Write this value to argi[0] at time 10.0 */ strcpy(charbuf, "01010101"); vpi_put_value(argi[0], &vpival, &t, vpiTransportDelay); /* Write this value to argi[1] at time 20.0 */ strcpy(charbuf, "x1x1x1x1"); t.real = 20.0; vpi_put_value(argi[1], &vpival, &t, vpiTransportDelay); /* Write this value to argi[2] at time 30.0 */ strcpy(charbuf, "0xz101xz"); t.real = 30.0; vpi_put_value(argi[2], &vpival, &t, vpiTransportDelay); return 0; }
static PLI_INT32 sys_writemem_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { int addr; FILE*file; char*fname = 0; unsigned cnt; s_vpi_value value; vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle mitem = 0; vpiHandle start_item = 0; vpiHandle stop_item = 0; int start_addr, stop_addr, addr_incr; int min_addr, max_addr; // Not used in this routine. /*======================================== Get parameters */ get_mem_params(argv, callh, name, &fname, &mitem, &start_item, &stop_item); if (fname == 0) return 0; /*======================================== Process parameters */ if (process_params(mitem, start_item, stop_item, callh, name, &start_addr, &stop_addr, &addr_incr, &min_addr, &max_addr)) { free(fname); return 0; } /* Open the data file. */ file = fopen(fname, "w"); if (file == 0) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s: Unable to open %s for writing.\n", name, fname); free(fname); return 0; } if (strcmp(name,"$writememb")==0) value.format = vpiBinStrVal; else value.format = vpiHexStrVal; /*======================================== Write memory file */ cnt = 0; for(addr=start_addr; addr!=stop_addr+addr_incr; addr+=addr_incr, ++cnt) { vpiHandle word_index; if (cnt%16 == 0) fprintf(file, "// 0x%08x\n", cnt); word_index = vpi_handle_by_index(mitem, addr); assert(word_index); vpi_get_value(word_index, &value); fprintf(file, "%s\n", value.value.str); } fclose(file); free(fname); return 0; }
static PLI_INT32 sys_readmem_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { int code, wwid, addr; FILE*file; char *fname = 0; s_vpi_value value; vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle mitem = 0; vpiHandle start_item = 0; vpiHandle stop_item = 0; /* start_addr and stop_addr are the parameters given to $readmem in the Verilog code. When not specified, start_addr is equal to the lower of the [left,right]_addr and stop_addr is equal to the higher of the [left,right]_addr. */ int start_addr, stop_addr, addr_incr; /* min_addr and max_addr are equal to start_addr and stop_addr if start_addr<stop_addr or vice versa if not... */ int min_addr, max_addr; /* This is the number of words that we need from the memory. */ unsigned word_count; /*======================================== Get parameters */ get_mem_params(argv, callh, name, &fname, &mitem, &start_item, &stop_item); if (fname == 0) return 0; /*======================================== Process parameters */ if (process_params(mitem, start_item, stop_item, callh, name, &start_addr, &stop_addr, &addr_incr, &min_addr, &max_addr)) { free(fname); return 0; } /* Open the data file. */ file = fopen(fname, "r"); /* Check to see if we have other directories to look for this file. */ if (file == 0 && sl_count > 0 && fname[0] != '/') { unsigned idx; char path[4096]; for (idx = 0; idx < sl_count; idx += 1) { snprintf(path, sizeof(path), "%s/%s", search_list[idx], fname); path[sizeof(path)-1] = 0; if ((file = fopen(path, "r"))) break; } } if (file == 0) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s: Unable to open %s for reading.\n", name, fname); free(fname); return 0; } /* We need this many words from the file. */ word_count = max_addr-min_addr+1; wwid = vpi_get(vpiSize, vpi_handle_by_index(mitem, min_addr)); /* variable that will be used by the lexer to pass values back to this code */ value.format = vpiVectorVal; value.value.vector = calloc((wwid+31)/32, sizeof(s_vpi_vecval)); /* Configure the readmem lexer */ if (strcmp(name,"$readmemb") == 0) sys_readmem_start_file(file, 1, wwid, value.value.vector); else sys_readmem_start_file(file, 0, wwid, value.value.vector); /*======================================== Read memory file */ /* Run through the input file and store the new contents in the memory */ addr = start_addr; while ((code = readmemlex()) != 0) { switch (code) { case MEM_ADDRESS: addr = value.value.vector->aval; if (addr < min_addr || addr > max_addr) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s(%s): address (0x%x) is out of range " "[0x%x:0x%x]\n", name, fname, addr, start_addr, stop_addr); goto bailout; } /* if there is an address in the memory file, then turn off any possible warnings about not having enough words to load the memory. This is standard behavior from 1364-2005. */ word_count = 0; break; case MEM_WORD: if (addr >= min_addr && addr <= max_addr) { vpiHandle word_index; word_index = vpi_handle_by_index(mitem, addr); assert(word_index); vpi_put_value(word_index, &value, 0, vpiNoDelay); if (word_count > 0) word_count -= 1; } else { vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s(%s): Too many words in the file for the " "requested range [%d:%d].\n", name, fname, start_addr, stop_addr); goto bailout; } addr += addr_incr; break; case MEM_ERROR: vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s(%s): Invalid input character: %s\n", name, fname, readmem_error_token); goto bailout; break; default: assert(0); break; } } /* Print a warning if there are not enough words in the data file. */ if (word_count > 0) { vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s(%s): Not enough words in the file for the " "requested range [%d:%d].\n", name, fname, start_addr, stop_addr); } bailout: free(value.value.vector); free(fname); fclose(file); destroy_readmem_lexor(); return 0; }
static PLI_INT32 sys_fopen_calltf(PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); s_vpi_value val; int fail = 0; char *mode_string = 0; unsigned idx; vpiHandle item = vpi_scan(argv); vpiHandle mode = vpi_scan(argv); unsigned len; /* Get the mode handle if it exists. */ if (mode) { val.format = vpiStringVal; vpi_get_value(mode, &val); /* Verify that we have a string and that it is not NULL. */ if (val.format != vpiStringVal || !*(val.value.str)) { vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's mode argument is not a valid string.\n", name); fail = 1; } /* Make sure the mode string is correct. */ if (strlen(val.value.str) > 3) { vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's mode argument (%s) is too long.\n", name, val.value.str); fail = 1; } else { unsigned bin = 0, plus = 0; switch (val.value.str[0]) { case 'r': case 'w': case 'a': for (idx = 1; idx < 3 ; idx++) { if (val.value.str[idx] == '\0') break; switch (val.value.str[idx]) { case 'b': if (bin) fail = 1; bin = 1; break; case '+': if (plus) fail = 1; plus = 1; break; default: fail = 1; break; } } if (! fail) break; default: vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's mode argument (%s) is invalid.\n", name, val.value.str); fail = 1; break; } } mode_string = strdup(val.value.str); vpi_free_object(argv); } /* Get the string form of the file name from the file name argument. */ val.format = vpiStringVal; vpi_get_value(item, &val); /* Verify that we have a string and that it is not NULL. */ if (val.format != vpiStringVal || !*(val.value.str)) { vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's file name argument is not a valid string.\n", name); fail = 1; if (mode) free(mode_string); } /* * Verify that the file name is composed of only printable * characters. */ len = strlen(val.value.str); for (idx = 0; idx < len; idx++) { if (! isprint(val.value.str[idx])) { char msg [64]; snprintf(msg, 64, "WARNING: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s %s's file name argument contains non-" "printable characters.\n", msg, name); vpi_printf("%*s \"%s\"\n", (int) strlen(msg), " ", val.value.str); fail = 1; if (mode) free(mode_string); } } /* If either the mode or file name are not valid just return. */ if (fail) return 0; val.format = vpiIntVal; if (mode) { val.value.integer = vpi_fopen(val.value.str, mode_string); free(mode_string); } else val.value.integer = vpi_mcd_open(val.value.str); vpi_put_value(callh, &val, 0, vpiNoDelay); return 0; }
int VpiSignalObjHdl::initialise(std::string &name, std::string &fq_name) { int32_t type = vpi_get(vpiType, GpiObjHdl::get_handle<vpiHandle>()); if ((vpiIntVar == type) || (vpiIntegerVar == type) || (vpiIntegerNet == type )) { m_num_elems = 1; } else { m_num_elems = vpi_get(vpiSize, GpiObjHdl::get_handle<vpiHandle>()); if (GpiObjHdl::get_type() == GPI_STRING) { m_indexable = false; // Don't want to iterate over indices m_range_left = 0; m_range_right = m_num_elems-1; } else if (GpiObjHdl::get_type() == GPI_REGISTER) { vpiHandle hdl = GpiObjHdl::get_handle<vpiHandle>(); m_indexable = vpi_get(vpiVector, hdl); if (m_indexable) { s_vpi_value val; vpiHandle iter; val.format = vpiIntVal; iter = vpi_iterate(vpiRange, hdl); /* Only ever need the first "range" */ if (iter != NULL) { vpiHandle rangeHdl = vpi_scan(iter); vpi_free_object(iter); if (rangeHdl != NULL) { vpi_get_value(vpi_handle(vpiLeftRange,rangeHdl),&val); check_vpi_error(); m_range_left = val.value.integer; vpi_get_value(vpi_handle(vpiRightRange,rangeHdl),&val); check_vpi_error(); m_range_right = val.value.integer; } else { LOG_CRITICAL("Unable to get Range for indexable object"); } } else { vpi_get_value(vpi_handle(vpiLeftRange,hdl),&val); check_vpi_error(); m_range_left = val.value.integer; vpi_get_value(vpi_handle(vpiRightRange,hdl),&val); check_vpi_error(); m_range_right = val.value.integer; } LOG_DEBUG("VPI: Indexable Object initialised with range [%d:%d] and length >%d<", m_range_left, m_range_right, m_num_elems); } } } LOG_DEBUG("VPI: %s initialised with %d elements", name.c_str(), m_num_elems); return GpiObjHdl::initialise(name, fq_name); }
int VpiArrayObjHdl::initialise(std::string &name, std::string &fq_name) { vpiHandle hdl = GpiObjHdl::get_handle<vpiHandle>(); m_indexable = true; int range_idx = 0; /* Need to determine if this is a pseudo-handle to be able to select the correct range */ std::string hdl_name = vpi_get_str(vpiName, hdl); /* Removing the hdl_name from the name will leave the psuedo-indices */ if (hdl_name.length() < name.length()) { std::string idx_str = name.substr(hdl_name.length()); while (idx_str.length() > 0) { std::size_t found = idx_str.find_first_of("]"); if (found != std::string::npos) { ++range_idx; idx_str = idx_str.substr(found+1); } else { break; } } } /* After determining the range_idx, get the range and set the limits */ vpiHandle iter = vpi_iterate(vpiRange, hdl); s_vpi_value val; val.format = vpiIntVal; if (iter != NULL) { vpiHandle rangeHdl; int idx = 0; while ((rangeHdl = vpi_scan(iter)) != NULL) { if (idx == range_idx) { break; } ++idx; } if (rangeHdl == NULL) { LOG_CRITICAL("Unable to get Range for indexable object"); } else { vpi_free_object(iter); // Need to free iterator since exited early vpi_get_value(vpi_handle(vpiLeftRange,rangeHdl),&val); check_vpi_error(); m_range_left = val.value.integer; vpi_get_value(vpi_handle(vpiRightRange,rangeHdl),&val); check_vpi_error(); m_range_right = val.value.integer; } } else if (range_idx == 0) { vpi_get_value(vpi_handle(vpiLeftRange,hdl),&val); check_vpi_error(); m_range_left = val.value.integer; vpi_get_value(vpi_handle(vpiRightRange,hdl),&val); check_vpi_error(); m_range_right = val.value.integer; } else { LOG_CRITICAL("Unable to get Range for indexable object"); } /* vpiSize will return a size that is incorrect for multi-dimensional arrays so use the range * to calculate the m_num_elems. * * For example: * wire [7:0] sig_t4 [0:3][7:4] * * The size of "sig_t4" will be reported as 16 through the vpi interface. */ if (m_range_left > m_range_right) { m_num_elems = m_range_left - m_range_right + 1; } else { m_num_elems = m_range_right - m_range_left + 1; } return GpiObjHdl::initialise(name, fq_name); }
static void scan_item(unsigned depth, vpiHandle item, int skip) { struct t_cb_data cb; struct vcd_info* info; const char* name; const char* ident; int nexus_id; /* list of types to iterate upon */ int i; static int types[] = { /* Value */ vpiNet, vpiReg, vpiVariables, /* Scope */ vpiFunction, vpiModule, vpiNamedBegin, vpiNamedFork, vpiTask, -1 }; switch (vpi_get(vpiType, item)) { case vpiMemoryWord: if (vpi_get(vpiConstantSelect, item) == 0) { /* Turn a non-constant array word select into a * constant word select. */ vpiHandle array = vpi_handle(vpiParent, item); PLI_INT32 idx = vpi_get(vpiIndex, item); item = vpi_handle_by_index(array, idx); } case vpiIntegerVar: case vpiBitVar: case vpiByteVar: case vpiShortIntVar: case vpiIntVar: case vpiLongIntVar: case vpiTimeVar: case vpiReg: case vpiNet: /* An array word is implicitly escaped so look for an * escaped identifier that this could conflict with. */ if (vpi_get(vpiType, item) == vpiMemoryWord && vpi_handle_by_name(vpi_get_str(vpiFullName, item), 0)) { vpi_printf("LXT2 warning: dumping array word %s will " "conflict with an escaped identifier.\n", vpi_get_str(vpiFullName, item)); } if (skip || vpi_get(vpiAutomatic, item)) break; name = vpi_get_str(vpiName, item); nexus_id = vpi_get(_vpiNexusId, item); if (nexus_id) { ident = find_nexus_ident(nexus_id); } else { ident = 0; } if (!ident) { char*tmp = create_full_name(name); ident = strdup_sh(&name_heap, tmp); free(tmp); if (nexus_id) set_nexus_ident(nexus_id, ident); info = new_vcd_info(); info->item = item; info->sym = lxt2_wr_symbol_add(dump_file, ident, 0 /* array rows */, vpi_get(vpiLeftRange, item), vpi_get(vpiRightRange, item), LXT2_WR_SYM_F_BITS); info->dmp_next = 0; cb.time = 0; cb.user_data = (char*)info; cb.value = NULL; cb.obj = item; cb.reason = cbValueChange; cb.cb_rtn = variable_cb_1; info->cb = vpi_register_cb(&cb); } else { char *n = create_full_name(name); lxt2_wr_symbol_alias(dump_file, ident, n, vpi_get(vpiSize, item)-1, 0); free(n); } break; case vpiRealVar: if (skip || vpi_get(vpiAutomatic, item)) break; name = vpi_get_str(vpiName, item); { char*tmp = create_full_name(name); ident = strdup_sh(&name_heap, tmp); free(tmp); } info = new_vcd_info(); info->item = item; info->sym = lxt2_wr_symbol_add(dump_file, ident, 0 /* array rows */, vpi_get(vpiSize, item)-1, 0, LXT2_WR_SYM_F_DOUBLE); info->dmp_next = 0; cb.time = 0; cb.user_data = (char*)info; cb.value = NULL; cb.obj = item; cb.reason = cbValueChange; cb.cb_rtn = variable_cb_1; info->cb = vpi_register_cb(&cb); break; case vpiModule: case vpiNamedBegin: case vpiTask: case vpiFunction: case vpiNamedFork: if (depth > 0) { int nskip; vpiHandle argv; const char* fullname = vpi_get_str(vpiFullName, item); #if 0 vpi_printf("LXT2 info: scanning scope %s, %u levels\n", fullname, depth); #endif nskip = vcd_scope_names_test(fullname); if (!nskip) vcd_scope_names_add(fullname); else vpi_printf("LXT2 warning: ignoring signals in " "previously scanned scope %s\n", fullname); name = vpi_get_str(vpiName, item); push_scope(name); for (i=0; types[i]>0; i++) { vpiHandle hand; argv = vpi_iterate(types[i], item); while (argv && (hand = vpi_scan(argv))) { scan_item(depth-1, hand, nskip); } } pop_scope(); } break; default: vpi_printf("LXT2 warning: $dumpvars: Unsupported parameter " "type (%s)\n", vpi_get_str(vpiType, item)); } }
int checkRetireInst_calltf(char *user_data) { db_t * db_ptr; unsigned int FS_PC; unsigned int V_PC; SS_WORD_TYPE FS_rdst_value; SS_WORD_TYPE V_rdst_value; vpiHandle systf_handle, arg_iterator, arg_handle, reg_handle; s_vpi_value arg1; s_vpi_value arg2; // s_vpi_value value_s; //unsigned long long instruction; /* obtain a handle to the system task instance. */ systf_handle = vpi_handle(vpiSysTfCall, 0); /* obtain handle to system task argument. */ arg_iterator = vpi_iterate(vpiArgument, systf_handle); reg_handle = vpi_scan(arg_iterator); /* read current value */ arg1.format = vpiIntVal; /* read value as a integer */ vpi_get_value(reg_handle, &arg1); V_PC = (unsigned int) arg1.value.integer; // Next value reg_handle = vpi_scan(arg_iterator); arg2.format = vpiIntVal; /* read value as a integer */ vpi_get_value(reg_handle, &arg2); V_rdst_value = (SS_WORD_TYPE) arg2.value.integer; // Pop from DB (head) db_ptr = THREAD[0]->get_instr(); FS_PC = (unsigned int) db_ptr->a_pc; if (db_ptr->a_num_rdst > 1) { vpi_printf("Double Word destination!!\n"); vpi_printf("Bye !!\n"); assert(0); } if (db_ptr->a_num_rdst == 1) FS_rdst_value = db_ptr->a_rdst[0].value; // Do the check if (V_PC != FS_PC) { vpi_printf("Retire PC Error!! "); vpi_printf("PC:%x Actual:%x\n",V_PC, FS_PC); assert(0); } if (db_ptr->a_num_rdst == 1) { if (V_rdst_value != FS_rdst_value) { vpi_printf("Rdst Value Error!! "); vpi_printf("Rdst:%x Actual:%x\n",V_rdst_value, FS_rdst_value); assert(0); } } /* free iterator memory */ vpi_free_object(arg_iterator); return(0); }
static PLI_INT32 ivl_method_next_calltf(PLI_BYTE8*data) { vpiHandle sys = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, sys); vpiHandle arg_enum = vpi_scan(argv); vpiHandle arg_item = vpi_scan(argv); vpiHandle arg_extra = vpi_scan(argv); vpiHandle enum_list = 0; vpiHandle memb = 0, first_memb = 0; long use_width = 0; long item_width = vpi_get(vpiSize, arg_item); s_vpi_value memb_value, item_value; assert(arg_extra == 0); item_value.format = vpiObjTypeVal; vpi_get_value(arg_item, &item_value); /* If this value is a vector value, then make a safe copy of the vector so that other vpi functions don't trash it. */ if (item_value.format == vpiVectorVal) { unsigned idx; unsigned hwid = (item_width - 1)/32 + 1; s_vpi_vecval*op = calloc(hwid, sizeof(s_vpi_vecval)); for (idx = 0 ; idx < hwid ; idx += 1) { op[idx].aval = item_value.value.vector[idx].aval; op[idx].bval = item_value.value.vector[idx].bval; } item_value.value.vector = op; } enum_list = vpi_iterate(vpiMember, arg_enum); assert(enum_list); /* Search for the current value in the member list. */ do { memb = vpi_scan(enum_list); if (first_memb == 0) { first_memb = memb; use_width = vpi_get(vpiSize, first_memb); assert(use_width == vpi_get(vpiSize, arg_item)); } if (memb == 0) break; memb_value.format = vpiObjTypeVal; vpi_get_value(memb, &memb_value); } while (! compare_value_eequal(&item_value, &memb_value, use_width)); if (memb != 0) memb = vpi_scan(enum_list); if (memb != 0) vpi_free_object(enum_list); if (memb == 0) { memb = first_memb; memb_value.format = vpiIntVal; } /* Free any stached copy of the vector. */ if (item_value.format == vpiVectorVal) free(item_value.value.vector); vpi_get_value(memb, &memb_value); vpi_put_value(sys, &memb_value, 0, vpiNoDelay); return 0; }
static PLI_INT32 sys_fseek_compiletf(PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle arg; /* Check that there are three numeric arguments. */ if (argv == 0) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s requires three arguments.\n", name); vpi_control(vpiFinish, 1); return 0; } /* Check that the first argument is numeric. */ if (! is_numeric_obj(vpi_scan(argv))) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's first argument must be numeric.\n", name); vpi_control(vpiFinish, 1); } /* Check that the second argument exists and is numeric. */ arg = vpi_scan(argv); if (! arg) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s requires a second (numeric) argument.\n", name); vpi_control(vpiFinish, 1); return 0; } if (!arg || !is_numeric_obj(arg)) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's second argument must be numeric.\n", name); vpi_control(vpiFinish, 1); } /* Check that the third argument exists and is numeric. */ arg = vpi_scan(argv); if (! arg) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s requires a third (numeric) argument.\n", name); vpi_control(vpiFinish, 1); return 0; } if (!arg || !is_numeric_obj(arg)) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's third argument must be numeric.\n", name); vpi_control(vpiFinish, 1); } /* Make sure there are no extra arguments. */ if (vpi_scan(argv) != 0) { char msg [64]; unsigned argc; snprintf(msg, 64, "ERROR: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); argc = 1; while (vpi_scan(argv)) argc += 1; vpi_printf("%s %s takes three arguments.\n", msg, name); vpi_printf("%*s Found %u extra argument%s.\n", (int) strlen(msg), " ", argc, argc == 1 ? "" : "s"); vpi_control(vpiFinish, 1); } return 0; }
static PLI_INT32 sys_fseek_calltf(PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle arg; s_vpi_value val; PLI_UINT32 fd_mcd; PLI_INT32 offset, oper; FILE *fp; /* Get the file pointer. */ arg = vpi_scan(argv); val.format = vpiIntVal; vpi_get_value(arg, &val); fd_mcd = val.value.integer; /* Get the offset. */ arg = vpi_scan(argv); val.format = vpiIntVal; vpi_get_value(arg, &val); offset = val.value.integer; /* Get the operation. */ arg = vpi_scan(argv); vpi_free_object(argv); val.format = vpiIntVal; vpi_get_value(arg, &val); oper = val.value.integer; /* Check that the operation is in the valid range. */ if ((oper < 0) || (oper > 2)) { vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's operation must be 0, 1 or 2 given %d.\n", name, oper); val.format = vpiIntVal; val.value.integer = EOF; vpi_put_value(callh, &val, 0, vpiNoDelay); return 0; } /* Return EOF if this is not a valid fd. */ fp = vpi_get_file(fd_mcd); if (!fp || IS_MCD(fd_mcd)) { vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd, name); val.format = vpiIntVal; val.value.integer = EOF; vpi_put_value(callh, &val, 0, vpiNoDelay); return 0; } val.format = vpiIntVal; val.value.integer = fseek(fp, offset, oper); vpi_put_value(callh, &val, 0 , vpiNoDelay); return 0; }
static void scan_item(unsigned depth, vpiHandle item, int skip) { struct t_cb_data cb; struct vcd_info* info; enum fstVarType type = FST_VT_MAX; enum fstScopeType stype = FST_ST_MAX; enum fstVarDir dir; const char *name; const char *fullname; char *escname; const char *ident; fstHandle new_ident; int nexus_id; unsigned size; PLI_INT32 item_type; /* Get the displayed type for the various $var and $scope types. */ /* Not all of these are supported now, but they should be in a * future development version. */ item_type = vpi_get(vpiType, item); switch (item_type) { case vpiNamedEvent: type = FST_VT_VCD_EVENT; break; case vpiIntVar: case vpiIntegerVar: type = FST_VT_VCD_INTEGER; break; case vpiParameter: type = FST_VT_VCD_PARAMETER; break; /* Icarus converts realtime to real. */ case vpiRealVar: type = FST_VT_VCD_REAL; break; case vpiMemoryWord: case vpiBitVar: case vpiByteVar: case vpiShortIntVar: case vpiLongIntVar: case vpiReg: type = FST_VT_VCD_REG; break; /* Icarus converts a time to a plain register. */ case vpiTimeVar: type = FST_VT_VCD_TIME; break; case vpiNet: switch (vpi_get(vpiNetType, item)) { case vpiWand: type = FST_VT_VCD_WAND; break; case vpiWor: type = FST_VT_VCD_WOR; break; case vpiTri: type = FST_VT_VCD_TRI; break; case vpiTri0: type = FST_VT_VCD_TRI0; break; case vpiTri1: type = FST_VT_VCD_TRI1; break; case vpiTriReg: type = FST_VT_VCD_TRIREG; break; case vpiTriAnd: type = FST_VT_VCD_TRIAND; break; case vpiTriOr: type = FST_VT_VCD_TRIOR; break; case vpiSupply1: type = FST_VT_VCD_SUPPLY1; break; case vpiSupply0: type = FST_VT_VCD_SUPPLY0; break; default: type = FST_VT_VCD_WIRE; break; } break; case vpiNamedBegin: stype = FST_ST_VCD_BEGIN; break; case vpiNamedFork: stype = FST_ST_VCD_FORK; break; case vpiFunction: stype = FST_ST_VCD_FUNCTION; break; case vpiGenScope: stype = FST_ST_VCD_GENERATE; break; case vpiModule: stype = FST_ST_VCD_MODULE; break; case vpiTask: stype = FST_ST_VCD_TASK; break; default: vpi_printf("FST warning: $dumpvars: Unsupported argument " "type (%s)\n", vpi_get_str(vpiType, item)); return; } /* Do some special processing/checking on array words. Dumping * array words is an Icarus extension. */ if (item_type == vpiMemoryWord) { /* Turn a non-constant array word select into a constant * word select. */ if (vpi_get(vpiConstantSelect, item) == 0) { vpiHandle array = vpi_handle(vpiParent, item); PLI_INT32 idx = vpi_get(vpiIndex, item); item = vpi_handle_by_index(array, idx); } /* An array word is implicitly escaped so look for an * escaped identifier that this could conflict with. */ /* This does not work as expected since we always find at * least the array word. We likely need a custom routine. */ if (vpi_get(vpiType, item) == vpiMemoryWord && vpi_handle_by_name(vpi_get_str(vpiFullName, item), 0)) { vpi_printf("FST warning: array word %s will conflict " "with an escaped identifier.\n", vpi_get_str(vpiFullName, item)); } } fullname = vpi_get_str(vpiFullName, item); /* Generate the $var or $scope commands. */ switch (item_type) { case vpiParameter: vpi_printf("FST sorry: $dumpvars: can not dump parameters.\n"); break; case vpiNamedEvent: case vpiIntegerVar: case vpiBitVar: case vpiByteVar: case vpiShortIntVar: case vpiIntVar: case vpiLongIntVar: case vpiRealVar: case vpiMemoryWord: case vpiReg: case vpiTimeVar: case vpiNet: /* If we are skipping all signal or this is in an automatic * scope then just return. */ if (skip || vpi_get(vpiAutomatic, item)) return; /* Skip this signal if it has already been included. * This can only happen for implicitly given signals. */ if (vcd_names_search(&fst_var, fullname)) return; /* Declare the variable in the FST file. */ name = vpi_get_str(vpiName, item); if (is_escaped_id(name)) { escname = malloc(strlen(name) + 2); sprintf(escname, "\\%s", name); } else escname = strdup(name); /* Some signals can have an alias so handle that. */ nexus_id = vpi_get(_vpiNexusId, item); ident = 0; if (nexus_id) ident = find_nexus_ident(nexus_id); /* Named events do not have a size, but other tools use * a size of 1 and some viewers do not accept a width of * zero so we will also use a width of one for events. */ if (item_type == vpiNamedEvent) size = 1; else size = vpi_get(vpiSize, item); /* The FST format supports a port direction so if the net * is a port set the direction to one of the following: * FST_VD_INPUT, FST_VD_OUTPUT or FST_VD_INOUT */ dir = FST_VD_IMPLICIT; if (size > 1 || vpi_get(vpiLeftRange, item) != 0) { char *buf = malloc(strlen(escname) + 65); sprintf(buf, "%s [%i:%i]", escname, (int)vpi_get(vpiLeftRange, item), (int)vpi_get(vpiRightRange, item)); new_ident = fstWriterCreateVar(dump_file, type, dir, size, buf, (fstHandle)(long)ident); free(buf); } else { new_ident = fstWriterCreateVar(dump_file, type, dir, size, escname, (fstHandle)(long)ident); } free(escname); if (!ident) { if (nexus_id) set_nexus_ident(nexus_id, (const char *)(long)new_ident); /* Add a callback for the signal. */ info = malloc(sizeof(*info)); info->time.type = vpiSimTime; info->item = item; info->handle = new_ident; info->scheduled = 0; cb.time = &info->time; cb.user_data = (char*)info; cb.value = NULL; cb.obj = item; cb.reason = cbValueChange; cb.cb_rtn = variable_cb_1; info->dmp_next = 0; info->next = vcd_list; vcd_list = info; info->cb = vpi_register_cb(&cb); } break; case vpiModule: case vpiGenScope: case vpiFunction: case vpiTask: case vpiNamedBegin: case vpiNamedFork: if (depth > 0) { char *instname; char *defname = NULL; /* list of types to iterate upon */ static int types[] = { /* Value */ vpiNamedEvent, vpiNet, /* vpiParameter, */ vpiReg, vpiVariables, /* Scope */ vpiFunction, vpiGenScope, vpiModule, vpiNamedBegin, vpiNamedFork, vpiTask, -1 }; int i; int nskip = (vcd_names_search(&fst_tab, fullname) != 0); /* We have to always scan the scope because the * depth could be different for this call. */ if (nskip) { vpi_printf("FST warning: ignoring signals in " "previously scanned scope %s.\n", fullname); } else { vcd_names_add(&fst_tab, fullname); } /* Set the file and line information for this scope. * Everything has instance information. Only a module * has separate definition information. */ instname = vpi_get_str(vpiFile, item); fstWriterSetSourceInstantiationStem(dump_file, instname, (int)vpi_get(vpiLineNo, item), 0); if (item_type == vpiModule) { fstWriterSetSourceStem(dump_file, vpi_get_str(vpiDefFile, item), (int)vpi_get(vpiDefLineNo, item), 0); } else { fstWriterSetSourceStem(dump_file, instname, (int)vpi_get(vpiLineNo, item), 0); } /* This must be done before the other name is fetched * and the string must always be freed */ if (item_type == vpiModule) { defname = strdup(vpi_get_str(vpiDefName, item)); } name = vpi_get_str(vpiName, item); /* If the two names match only use the vpiName. */ if (defname && (strcmp(defname, name) == 0)) { free(defname); defname = NULL; } fstWriterSetScope(dump_file, stype, name, defname); free(defname); for (i=0; types[i]>0; i++) { vpiHandle hand; vpiHandle argv = vpi_iterate(types[i], item); while (argv && (hand = vpi_scan(argv))) { scan_item(depth-1, hand, nskip); } } /* Sort any signals that we added above. */ fstWriterSetUpscope(dump_file); } break; } }
static PLI_INT32 sys_mem_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle arg; /* Check that there is a file name argument. */ if (argv == 0) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s requires two arguments.\n", name); vpi_control(vpiFinish, 1); return 0; } if (! is_string_obj(vpi_scan(argv))) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's first argument must be a file name (string).\n", name); vpi_control(vpiFinish, 1); } /* Check that there is a memory argument. */ arg = vpi_scan(argv); if (! arg) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s requires a second (memory) argument.\n", name); vpi_control(vpiFinish, 1); return 0; } if (vpi_get(vpiType, arg) != vpiMemory) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's second argument must be a memory.\n", name); vpi_control(vpiFinish, 1); } /* Check if there is a starting address argument. */ arg = vpi_scan(argv); if (! arg) return 0; if (! is_numeric_obj(arg)) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's third argument must be a start address " "(numeric).\n", name); vpi_control(vpiFinish, 1); } /* Check if there is a finish address argument. */ arg = vpi_scan(argv); if (! arg) return 0; if (! is_numeric_obj(arg)) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's fourth argument must be a finish address " "(numeric).\n", name); vpi_control(vpiFinish, 1); } /* Make sure there are no extra arguments. */ check_for_extra_args(argv, callh, name, "four arguments", 1); return 0; }
static PLI_INT32 sys_dumpvars_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle item; s_vpi_value value; unsigned depth = 0; (void)name; /* Parameter is not used. */ if (dump_file == 0) { open_dumpfile(callh); if (dump_file == 0) { if (argv) vpi_free_object(argv); return 0; } } if (install_dumpvars_callback()) { if (argv) vpi_free_object(argv); return 0; } /* Get the depth if it exists. */ if (argv) { value.format = vpiIntVal; vpi_get_value(vpi_scan(argv), &value); depth = value.value.integer; } if (!depth) depth = 10000; /* This dumps all the modules in the design if none are given. */ if (!argv || !(item = vpi_scan(argv))) { argv = vpi_iterate(vpiModule, 0x0); assert(argv); /* There must be at least one top level module. */ item = vpi_scan(argv); } for ( ; item; item = vpi_scan(argv)) { char *scname; const char *fullname; int add_var = 0; int dep; PLI_INT32 item_type = vpi_get(vpiType, item); /* If this is a signal make sure it has not already * been included. */ switch (item_type) { case vpiIntegerVar: case vpiBitVar: case vpiByteVar: case vpiShortIntVar: case vpiIntVar: case vpiLongIntVar: case vpiMemoryWord: case vpiNamedEvent: case vpiNet: case vpiParameter: case vpiRealVar: case vpiReg: case vpiTimeVar: /* Warn if the variables scope (which includes the * variable) or the variable itself was already * included. A scope does not automatically include * memory words so do not check the scope for them. */ scname = strdup(vpi_get_str(vpiFullName, vpi_handle(vpiScope, item))); fullname = vpi_get_str(vpiFullName, item); if (((item_type != vpiMemoryWord) && vcd_names_search(&fst_tab, scname)) || vcd_names_search(&fst_var, fullname)) { vpi_printf("FST warning: skipping signal %s, " "it was previously included.\n", fullname); free(scname); continue; } else { add_var = 1; } free(scname); } dep = draw_scope(item, callh); scan_item(depth, item, 0); /* The scope list must be sorted after we scan an item. */ vcd_names_sort(&fst_tab); while (dep--) fstWriterSetUpscope(dump_file); /* Add this signal to the variable list so we can verify it * is not included twice. This must be done after it has * been added */ if (add_var) { vcd_names_add(&fst_var, vpi_get_str(vpiFullName, item)); vcd_names_sort(&fst_var); } } return 0; }
static PLI_INT32 sys_readmempath_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle paths = vpi_scan(argv); s_vpi_value val; unsigned len, idx; char *path; vpi_free_object(argv); /* Get the search path string. */ val.format = vpiStringVal; vpi_get_value(paths, &val); /* Verify that we have a string and that it is not NULL. */ if (val.format != vpiStringVal || !*(val.value.str)) { vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's argument (%s) is not a valid string.\n", name, vpi_get_str(vpiType, paths)); return 0; } /* * Verify that the search path is composed of only printable * characters. */ len = strlen(val.value.str); for (idx = 0; idx < len; idx++) { if (! isprint((int)val.value.str[idx])) { char msg[64]; char *esc_path = as_escaped(val.value.str); snprintf(msg, sizeof(msg), "WARNING: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); msg[sizeof(msg)-1] = 0; vpi_printf("%s %s's argument contains non-printable " "characters.\n", msg, name); vpi_printf("%*s \"%s\"\n", (int) strlen(msg), " ", esc_path); free(esc_path); return 0; } } /* Clear the old list before creating the new list. */ free_readmempath(NULL); /* * Break the string into individual paths and add them to the list. * Print a warning if the path is not valid. */ for (path = strtok(val.value.str, ":"); path; path = strtok(NULL, ":")) { int res; struct stat sb; /* Warn the user if the path is not valid. */ res = stat(path, &sb); if (res == 0) { if (!S_ISDIR(sb.st_mode)) { vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's path element \"%s\" is not a " "directory!\n", name, path); continue; } } else { vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s could not find directory \"%s\"!\n", name, path); continue; } /* Add a valid search path element to the list. */ sl_count += 1; search_list = (char **) realloc(search_list, sizeof(char **)*sl_count); search_list[sl_count-1] = strdup(path); } return 0; }
/* $dumpvars takes a variety of arguments. */ PLI_INT32 sys_dumpvars_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle arg; /* No arguments is OK, dump everything. */ if (argv == 0) return 0; /* The first argument is the numeric level. */ if (! is_numeric_obj(vpi_scan(argv))) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's argument must be numeric.\n", name); vpi_control(vpiFinish, 1); } /* The rest of the arguments are either a module or a variable. */ while ((arg=vpi_scan(argv)) != NULL) { switch(vpi_get(vpiType, arg)) { case vpiMemoryWord: /* * We need to allow non-constant selects to support the following: * * for (lp = 0; lp < max ; lp = lp + 1) $dumpvars(0, array[lp]); * * We need to do a direct callback on the selected element vs using * the &A<> structure. The later will not give us what we want. * This is implemented in the calltf routine. */ #if 0 if (vpi_get(vpiConstantSelect, arg) == 0) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s cannot dump a non-constant select %s.\n", name, vpi_get_str(vpiType, arg)); vpi_control(vpiFinish, 1); } #endif /* The module types. */ case vpiModule: case vpiTask: case vpiFunction: case vpiNamedBegin: case vpiNamedFork: /* The variable types. */ #if 0 case vpiParameter: /* A constant! */ #endif case vpiNet: case vpiReg: case vpiIntegerVar: case vpiTimeVar: case vpiRealVar: case vpiNamedEvent: break; case vpiParameter: /* A constant! */ vpi_printf("SORRY: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s cannot currently dump a parameter.\n", name); break; default: vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s cannot dump a %s.\n", name, vpi_get_str(vpiType, arg)); vpi_control(vpiFinish, 1); } } return 0; }
static int process_params(vpiHandle mitem, vpiHandle start_item, vpiHandle stop_item, vpiHandle callh, const char *name, int *start_addr, int *stop_addr, int *addr_incr, int *min_addr, int *max_addr) { s_vpi_value val; int left_addr, right_addr; /* Get left addr of memory */ val.format = vpiIntVal; vpi_get_value(vpi_handle(vpiLeftRange, mitem), &val); left_addr = val.value.integer; /* Get right addr of memory */ val.format = vpiIntVal; vpi_get_value(vpi_handle(vpiRightRange, mitem), &val); right_addr = val.value.integer; /* Get start_addr, stop_addr and addr_incr */ if (! start_item) { *start_addr = left_addr<right_addr ? left_addr : right_addr; *stop_addr = left_addr<right_addr ? right_addr : left_addr; *addr_incr = 1; } else { val.format = vpiIntVal; vpi_get_value(start_item, &val); *start_addr = val.value.integer; if (! stop_item) { *stop_addr = left_addr<right_addr ? right_addr : left_addr; *addr_incr = 1; } else { val.format = vpiIntVal; vpi_get_value(stop_item, &val); *stop_addr = val.value.integer; *addr_incr = *start_addr<*stop_addr ? 1 : -1; } } /* Find the minimum and maximum address. */ *min_addr = *start_addr<*stop_addr ? *start_addr : *stop_addr ; *max_addr = *start_addr<*stop_addr ? *stop_addr : *start_addr; /* If the range is not fully specified and the left address is * greater than the right address. Print a warning that this * code follows 1364-2005. * * If we passed a generation flag we could do the correct thing * for 1364-1995 and 1364-2001 instead of this general warning * or we could only show the warning when using 2001/1995. */ if (!stop_item && (left_addr > right_addr)) { vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s: Standard inconsistency, following 1364-2005.\n", name); } /* Check that start_addr and stop_addr are within the memory range */ if (left_addr < right_addr) { if (*start_addr < left_addr || *start_addr > right_addr) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s: Start address %d is out of bounds for memory " "\'%s[%d:%d]\'!\n", name, *start_addr, vpi_get_str(vpiFullName, mitem), left_addr, right_addr); return 1; } if (*stop_addr < left_addr || *stop_addr > right_addr) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s: Finish address %d is out of bounds for memory " "\'%s[%d:%d]\'!\n", name, *stop_addr, vpi_get_str(vpiFullName, mitem), left_addr, right_addr); return 1; } } else { if (*start_addr < right_addr || *start_addr > left_addr) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s: Start address %d is out of bounds for memory " "\'%s[%d:%d]\'!\n", name, *start_addr, vpi_get_str(vpiFullName, mitem), left_addr, right_addr); return 1; } if (*stop_addr < right_addr || *stop_addr > left_addr) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s: Finish address %d is out of bounds for memory " "\'%s[%d:%d]\'!\n", name, *stop_addr, vpi_get_str(vpiFullName, mitem), left_addr, right_addr); return 1; } } return 0; }
/* * The runtime code for $countdrivers(). */ static PLI_INT32 sys_countdrivers_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle arg; unsigned idx; unsigned counts[4]; unsigned num_drivers; s_vpi_value val; /* All returned values are integers. */ val.format = vpiIntVal; /* Get the base net reference and bit select */ idx = 0; arg = vpi_scan(argv); assert(arg); if (vpi_get(vpiType, arg) == vpiPartSelect) { idx = vpi_get(vpiLeftRange, arg); arg = vpi_handle(vpiParent, arg); assert(arg); } /* Get the net driver counts from the runtime. */ vpip_count_drivers(arg, idx, counts); num_drivers = counts[0] + counts[1] + counts[2]; /* Handle optional net_is_forced argument. */ arg = vpi_scan(argv); if (arg == 0) goto args_done; val.value.integer = counts[3]; vpi_put_value(arg, &val, 0, vpiNoDelay); /* Handle optional number_of_01x_drivers argument. */ arg = vpi_scan(argv); if (arg == 0) goto args_done; val.value.integer = num_drivers; vpi_put_value(arg, &val, 0, vpiNoDelay); /* Handle optional number_of_0_drivers argument. */ arg = vpi_scan(argv); if (arg == 0) goto args_done; val.value.integer = counts[0]; vpi_put_value(arg, &val, 0, vpiNoDelay); /* Handle optional number_of_1_drivers argument. */ arg = vpi_scan(argv); if (arg == 0) goto args_done; val.value.integer = counts[1]; vpi_put_value(arg, &val, 0, vpiNoDelay); /* Handle optional number_of_x_drivers argument. */ arg = vpi_scan(argv); if (arg == 0) goto args_done; val.value.integer = counts[2]; vpi_put_value(arg, &val, 0, vpiNoDelay); /* Free the argument iterator. */ vpi_free_object(argv); args_done: val.value.integer = (num_drivers > 1) ? 1 : 0; vpi_put_value(callh, &val, 0, vpiNoDelay); return 0; }
static int sys_dumpvars_calltf(char*name) { unsigned depth; s_vpi_value value; vpiHandle item = 0; vpiHandle sys = vpi_handle(vpiSysTfCall, 0); vpiHandle argv; if (dump_file == 0) { open_dumpfile(); if (dump_file == 0) return 0; } if (install_dumpvars_callback()) { return 0; } argv = vpi_iterate(vpiArgument, sys); depth = 0; if (argv && (item = vpi_scan(argv))) switch (vpi_get(vpiType, item)) { case vpiConstant: case vpiNet: case vpiReg: case vpiIntegerVar: case vpiMemoryWord: value.format = vpiIntVal; vpi_get_value(item, &value); depth = value.value.integer; break; } if (!depth) depth = 10000; if (!argv) { // $dumpvars; // search for the toplevel module vpiHandle parent = vpi_handle(vpiScope, sys); while (parent) { item = parent; parent = vpi_handle(vpiScope, item); } } else if (!item || !(item = vpi_scan(argv))) { // $dumpvars(level); // $dumpvars(); // dump the current scope item = vpi_handle(vpiScope, sys); argv = 0x0; } for ( ; item; item = argv ? vpi_scan(argv) : 0x0) { int dep = draw_scope(item); vcd_names_sort(&vcd_tab); scan_item(depth, item, 0); while (dep--) { fprintf(dump_file, "$upscope $end\n"); } } return 0; }
static PLI_INT32 sys_value_plusargs_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { s_vpi_vlog_info info; s_vpi_value fmt; s_vpi_value res; char msg[64]; char*cp; int idx; int flag = 0; size_t slen, len; vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); fmt.format = vpiStringVal; vpi_get_value(vpi_scan(argv), &fmt); /* Check for the start of a format string. */ cp = strchr(fmt.value.str, '%'); if (cp == 0) { snprintf(msg, sizeof(msg), "ERROR: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); msg[sizeof(msg)-1] = 0; vpi_printf("%s %s is missing a format code.\n", msg, name); vpi_printf("%*s \"%s\".\n", (int)strlen(msg), " ", fmt.value.str); vpi_control(vpiFinish, 1); return 0; } /* This is the length of string we will look for. */ slen = cp - fmt.value.str; /* Skip a zero. */ cp += 1; if (*cp == '0') cp += 1; /* Check the format code. */ switch (*cp) { case 'd': case 'D': case 'o': case 'O': case 'h': case 'H': case 'x': case 'X': case 'b': case 'B': case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': case 's': case 'S': break; default: snprintf(msg, sizeof(msg), "ERROR: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); msg[sizeof(msg)-1] = 0; vpi_printf("%s %s has an invalid format string:\n", msg, name); vpi_printf("%*s \"%s\".\n", (int)strlen(msg), " ", fmt.value.str); vpi_control(vpiFinish, 1); return 0; } /* Warn if there is any trailing garbage. */ if (*(cp+1) != '\0') { snprintf(msg, sizeof(msg), "WARNING: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); msg[sizeof(msg)-1] = 0; vpi_printf("%s Skipping trailing garbage in %s's format string:\n", msg, name); vpi_printf("%*s \"%s\".\n", (int)strlen(msg), " ", fmt.value.str); *(cp+1) = '\0'; } vpi_get_vlog_info(&info); /* Look for a +arg that matches the prefix supplied. */ for (idx = 0 ; idx < info.argc ; idx += 1) { char*sp, *tp, *end; size_t sp_len; /* Skip arguments that are not +args. */ if (info.argv[idx][0] != '+') continue; len = strlen(info.argv[idx]+1); if (len < slen) continue; if (strncmp(fmt.value.str, info.argv[idx]+1, slen) != 0) continue; sp = info.argv[idx]+1+slen; sp_len = strlen(sp); switch (*cp) { case 'd': case 'D': res.format = vpiDecStrVal; /* A decimal string can set the value to "x" or "z". */ if (sp_len == strspn(sp, "xX_") || sp_len == strspn(sp, "zZ_")) { res.value.str = sp; /* A decimal string must contain only these characters. * A decimal string can not start with an "_" character. * A "-" can only be at the start of the string. */ } else if (sp_len != strspn(sp, "-0123456789_") || *sp == '_' || ((tp = strrchr(sp, '-')) && tp != sp)) { res.value.str = "x"; snprintf(msg, sizeof(msg), "WARNING: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); msg[sizeof(msg)-1] = 0; vpi_printf("%s Invalid decimal value passed to %s:\n", msg, name); vpi_printf("%*s \"%s\".\n", (int)strlen(msg), " ", sp); } else { res.value.str = sp; } break; case 'o': case 'O': res.format = vpiOctStrVal; /* An octal string must contain only these characters. * An octal string can not start with an "_" character. * A "-" can only be at the start of the string. */ if (sp_len != strspn(sp, "-01234567_xXzZ") || *sp == '_' || ((tp = strrchr(sp, '-')) && tp != sp)) { res.value.str = "x"; snprintf(msg, sizeof(msg), "WARNING: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); msg[sizeof(msg)-1] = 0; vpi_printf("%s Invalid octal value passed to %s:\n", msg, name); vpi_printf("%*s \"%s\".\n", (int)strlen(msg), " ", sp); } else { res.value.str = sp; } break; case 'h': case 'H': case 'x': case 'X': res.format = vpiHexStrVal; /* A hex. string must contain only these characters. * A hex. string can not start with an "_" character. * A "-" can only be at the start of the string. */ if (sp_len != strspn(sp, "-0123456789aAbBcCdDeEfF_xXzZ") || *sp == '_' || ((tp = strrchr(sp, '-')) && tp != sp)) { res.value.str = "x"; snprintf(msg, sizeof(msg), "WARNING: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); msg[sizeof(msg)-1] = 0; vpi_printf("%s Invalid hex value passed to %s:\n", msg, name); vpi_printf("%*s \"%s\".\n", (int)strlen(msg), " ", sp); } else { res.value.str = sp; } break; case 'b': case 'B': res.format = vpiBinStrVal; /* A binary string must contain only these characters. * A binary string can not start with an "_" character. * A "-" can only be at the start of the string. */ if (sp_len != strspn(sp, "-01_xXzZ") || *sp == '_' || ((tp = strrchr(sp, '-')) && tp != sp)) { res.value.str = "x"; snprintf(msg, sizeof(msg), "WARNING: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); msg[sizeof(msg)-1] = 0; vpi_printf("%s Invalid binary value passed to %s:\n", msg, name); vpi_printf("%*s \"%s\".\n", (int)strlen(msg), " ", sp); } else { res.value.str = sp; } break; case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': res.format = vpiRealVal; res.value.real = strtod(sp, &end); /* If we didn't get a full conversion print a warning. */ if (*end) { /* We had an invalid value passed. */ if (end == sp) { snprintf(msg, sizeof(msg), "WARNING: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); msg[sizeof(msg)-1] = 0; vpi_printf("%s Invalid real value passed to " "%s:\n", msg, name); vpi_printf("%*s \"%s\".\n", (int)strlen(msg), " ", sp); /* We have extra garbage at the end. */ } else { snprintf(msg, sizeof(msg), "WARNING: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); msg[sizeof(msg)-1] = 0; vpi_printf("%s Extra character(s) \"%s\" found " "in %s's real string:\n", msg, end, name); vpi_printf("%*s \"%s\".\n", (int)strlen(msg), " ", sp); } } break; case 's': case 'S': res.format = vpiStringVal; res.value.str = sp; break; default: assert(0); } vpi_put_value(vpi_scan(argv), &res, 0, vpiNoDelay); flag = 1; break; } res.format = vpiIntVal; res.value.integer = flag; vpi_put_value(callh, &res, 0, vpiNoDelay); vpi_free_object(argv); return 0; }
PLI_INT32 cmt_send_comp(PLI_BYTE8 *user_data) { (void) user_data; vpiHandle systf_handle, arg_handle, arg_iter = NULL; PLI_INT32 arg_type; bool err = false; systf_handle = vpi_handle(vpiSysTfCall, NULL); arg_iter = vpi_iterate(vpiArgument, systf_handle); if (arg_iter == NULL) { vpi_printf("ERROR: $cmt_send takes at least 4 arguments\n"); err = true; goto SEND_COMP_FINISH; } //scan for first argument arg_handle = vpi_scan(arg_iter); arg_type = vpi_get(vpiType, arg_handle); if ( (arg_type != vpiConstant) && (arg_type != vpiIntegerVar) && (arg_type != vpiReg) && (arg_type != vpiNet) ) { vpi_printf("first argument to $cmt_send should be the id of the cmt computation."); err = true; goto SEND_COMP_FINISH; } //scan for second arguement arg_handle = vpi_scan(arg_iter); if (arg_handle == NULL) { arg_iter = NULL; // according to the standard, once vpi_scan returns NULL, the iterator is freed vpi_printf("ERROR: $cmt_send takes at least 4 arguments\n"); err = true; goto SEND_COMP_FINISH; } arg_type = vpi_get(vpiType, arg_handle); if ( (arg_type != vpiConstant) && (arg_type != vpiIntegerVar) && (arg_type != vpiReg) && (arg_type != vpiNet)) { vpi_printf("ERROR: Second argument to $cmt_send should be an integer constant CMT_*\n"); err = true; goto SEND_COMP_FINISH; } s_vpi_value arg_val = {0,}; arg_val.format = vpiIntVal; vpi_get_value(arg_handle, &arg_val); int requestType = arg_val.value.integer; #ifdef DEBUG vpi_printf("requestType in cmt_send: %d\n", requestType); #endif //scan for third arguement arg_handle = vpi_scan(arg_iter); if (arg_handle == NULL) { arg_iter = NULL; // according to the standard, once vpi_scan returns NULL, the iterator is freed vpi_printf("ERROR: $cmt_send takes at least 4 arguments\n"); err = true; goto SEND_COMP_FINISH; } arg_type = vpi_get(vpiType, arg_handle); if ( (arg_type != vpiReg) && (arg_type != vpiMemory) && (arg_type != vpiMemoryWord) && (arg_type != vpiNetArray) && (arg_type != vpiRegArray) ) { vpi_printf("ERROR: third argument to $cmt_send should be the field elements to send.\n"); vpi_printf("arg_type: %d\n", arg_type); err = true; goto SEND_COMP_FINISH; } //scan for fourth argument arg_handle = vpi_scan(arg_iter); if (arg_handle == NULL) { arg_iter = NULL; // according to the standard, once vpi_scan returns NULL, the iterator is freed vpi_printf("ERROR: $cmt_request takes at least 4 arguments\n"); err = true; goto SEND_COMP_FINISH; } arg_type = vpi_get(vpiType, arg_handle); if ( (arg_type != vpiConstant) && (arg_type != vpiParameter) ) { vpi_printf("ERROR: fourth argument to $cmt_send should be an integer specifying how many elements to send (CMT_OUTPUT, CMT_H) or the layer (CMT_F012).\n"); err = true; goto SEND_COMP_FINISH; } if (!isValidSend(requestType)) { arg_iter = NULL; vpi_printf("ERROR: Invalid reuquestType constant in $cmt_send\n"); err = true; goto SEND_COMP_FINISH; } if ((requestType == CMT_F012) || (requestType == CMT_H)) { //need a 5th argument in this case. arg_handle = vpi_scan(arg_iter); if (arg_handle == NULL) { arg_iter = NULL; // according to the standard, once vpi_scan returns NULL, the iterator is freed vpi_printf("ERROR: $cmt_send: you requested CMT_F012 without specifying a round, or CMT_H, without specifying a layer.\n"); err = true; goto SEND_COMP_FINISH; } arg_type = vpi_get(vpiType, arg_handle); if ( (arg_type != vpiConstant) && (arg_type != vpiParameter) && (arg_type != vpiIntegerVar) && (arg_type != vpiReg) && (arg_type != vpiNet) ) { vpi_printf("ERROR: fifth argument to $cmt_send should be an integer specifying round or layer.\n"); err = true; goto SEND_COMP_FINISH; } } if (vpi_scan(arg_iter) != NULL) { vpi_printf("ERROR: $cmt_send takes no more than 5 arguments.\n"); err = true; goto SEND_COMP_FINISH; } else { // vpi_scan(arg_iter) returned NULL, so arg_iter was automatically freed arg_iter = NULL; } SEND_COMP_FINISH: // free the iterator unless it's already been freed if ( (arg_iter != NULL) && (vpi_scan(arg_iter) != NULL) ) { vpi_free_object(arg_iter); } if (err) { vpi_control(vpiFinish, 1); } return 0; }
static PLI_INT32 sys_value_plusargs_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle arg; /* Check that there are arguments. */ if (argv == 0) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s requires two arguments.\n", name); vpi_control(vpiFinish, 1); return 0; } /* Check that the first argument is a string. */ arg = vpi_scan(argv); assert(arg != 0); if ( ! is_string_obj(arg)) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's first argument must be a string.\n", name); vpi_control(vpiFinish, 1); return 0; } arg = vpi_scan(argv); if (! arg) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's requires a second variable argument.\n", name); vpi_control(vpiFinish, 1); return 0; } switch (vpi_get(vpiType, arg)) { case vpiReg: case vpiIntegerVar: case vpiBitVar: case vpiByteVar: case vpiShortIntVar: case vpiIntVar: case vpiLongIntVar: case vpiRealVar: case vpiTimeVar: break; default: vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's second argument must be a variable, found a %s.\n", name, vpi_get_str(vpiType, arg)); vpi_control(vpiFinish, 1); return 0; } /* Make sure there are no extra arguments. */ check_for_extra_args(argv, callh, name, "two arguments", 0); return 0; }
PLI_INT32 cmt_request_comp(PLI_BYTE8 * user_data) { (void) user_data; vpiHandle systf_handle, arg_handle, arg_iter = NULL; PLI_INT32 arg_type; bool err = false; systf_handle = vpi_handle(vpiSysTfCall, NULL); arg_iter = vpi_iterate(vpiArgument, systf_handle); if (arg_iter == NULL) { vpi_printf("ERROR: $cmt_request takes at least 3 arguments\n"); err = true; goto REQUEST_COMP_FINISH; } //scan for first argument arg_handle = vpi_scan(arg_iter); arg_type = vpi_get(vpiType, arg_handle); if ( (arg_type != vpiConstant) && (arg_type != vpiIntegerVar) && (arg_type != vpiReg) && (arg_type != vpiNet) ) { vpi_printf("ERROR: First argument to $cmt_request should be the id of the cmt computation.\n"); err = true; goto REQUEST_COMP_FINISH; } //scan for second argument arg_handle = vpi_scan(arg_iter); if (arg_handle == NULL) { arg_iter = NULL; // according to the standard, once vpi_scan returns NULL, the iterator is freed vpi_printf("ERROR: $cmt_request takes at least 4 arguments\n"); err = true; goto REQUEST_COMP_FINISH; } arg_type = vpi_get(vpiType, arg_handle); if ( (arg_type != vpiConstant) && (vpi_get(vpiConstType, arg_handle) != vpiDecConst ) ) { vpi_printf("ERROR: second argument to $cmt_request should be an integer constant CMT_*\n"); err = true; goto REQUEST_COMP_FINISH; } s_vpi_value arg_val = {0,}; arg_val.format = vpiIntVal; vpi_get_value(arg_handle, &arg_val); int requestType = arg_val.value.integer; if (!isValidGetRequest(requestType)) { arg_iter = NULL; vpi_printf("ERROR: Invalid reuquestType constant in $cmt_request\n"); err = true; goto REQUEST_COMP_FINISH; } //scan for third argument arg_handle = vpi_scan(arg_iter); if (arg_handle == NULL) { arg_iter = NULL; // according to the standard, once vpi_scan returns NULL, the iterator is freed vpi_printf("ERROR: $cmt_request takes at least 4 arguments\n"); err = true; goto REQUEST_COMP_FINISH; } arg_type = vpi_get(vpiType, arg_handle); if ((arg_type != vpiReg) && (arg_type != vpiMemory) && (arg_type != vpiMemoryWord) && (arg_type != vpiRegArray) && (arg_type != vpiNetArray) ) { vpi_printf("ERROR: third argument to $cmt_request should be a vector of registers to send\n"); err = true; goto REQUEST_COMP_FINISH; } if (requestType == CMT_R || requestType == CMT_TAU) { if ((arg_type != vpiMemoryWord) && (arg_type != vpiReg)) { vpi_printf("ERROR: if requesting CMT_R or CMT_TAU, 3rd argument should be a single registor or memory word.\n"); } } //scan for fourth argument arg_handle = vpi_scan(arg_iter); if (arg_handle == NULL) { arg_iter = NULL; // according to the standard, once vpi_scan returns NULL, the iterator is freed vpi_printf("ERROR: $cmt_request takes at least 4 arguments\n"); err = true; goto REQUEST_COMP_FINISH; } arg_type = vpi_get(vpiType, arg_handle); if ( (arg_type != vpiConstant) && (arg_type != vpiParameter) ) { vpi_printf("ERROR: fourth argument to $cmt_request should be an integer specifying how many elements, or the layer of the computation. (%d) \n", arg_type); err = true; goto REQUEST_COMP_FINISH; } if ( (requestType == CMT_R) || (requestType == CMT_QI) ) { //scan for fifth argument arg_handle = vpi_scan(arg_iter); if (arg_handle == NULL) { arg_iter = NULL; // according to the standard, once vpi_scan returns NULL, the iterator is freed vpi_printf("ERROR: $cmt_request request requires 5 arguments when requesting CMT_R or CMT_QI.\n"); err = true; goto REQUEST_COMP_FINISH; } arg_type = vpi_get(vpiType, arg_handle); if ( (arg_type != vpiConstant) && (arg_type != vpiParameter) && (arg_type != vpiIntegerVar) && (arg_type != vpiReg) && (arg_type != vpiNet) ) { vpi_printf("ERROR: fifth argument to $cmt_request should be an integer specifying how many elements of QI, or which round of sumcheck, for R. \n"); err = true; goto REQUEST_COMP_FINISH; } } if (vpi_scan(arg_iter) != NULL) { vpi_printf("ERROR: $cmt_request takes four or five arguments"); err = true; goto REQUEST_COMP_FINISH; } else { // vpi_scan(arg_iter) returned NULL, so arg_iter was automatically freed arg_iter = NULL; } REQUEST_COMP_FINISH: // free the iterator unless it's already been freed if ( (arg_iter != NULL) && (vpi_scan(arg_iter) != NULL) ) { vpi_free_object(arg_iter); } if (err) { vpi_control(vpiFinish, 1); } return 0; }
static PLI_INT32 sys_fgets_calltf(PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle regh; vpiHandle arg; s_vpi_value val; PLI_UINT32 fd_mcd; FILE *fp; PLI_INT32 reg_size; char*text; (void) name; /* Not used! */ /* Get the register handle. */ regh = vpi_scan(argv); /* Get the file/MCD descriptor. */ arg = vpi_scan(argv); vpi_free_object(argv); val.format = vpiIntVal; vpi_get_value(arg, &val); fd_mcd = val.value.integer; /* Return zero if this is not a valid fd. */ fp = vpi_get_file(fd_mcd); if (!fp || IS_MCD(fd_mcd)) { vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd, name); val.format = vpiIntVal; val.value.integer = 0; vpi_put_value(callh, &val, 0, vpiNoDelay); return 0; } /* Get the register size in bytes and allocate the buffer. */ reg_size = vpi_get(vpiSize, regh) / 8; text = malloc(reg_size + 1); /* Read in the bytes. Return 0 if there was an error. */ if (fgets(text, reg_size+1, fp) == 0) { val.format = vpiIntVal; val.value.integer = 0; vpi_put_value(callh, &val, 0, vpiNoDelay); free(text); return 0; } /* Return the number of character read. */ val.format = vpiIntVal; val.value.integer = strlen(text); vpi_put_value(callh, &val, 0, vpiNoDelay); /* Return the characters to the register. */ val.format = vpiStringVal; val.value.str = text; vpi_put_value(regh, &val, 0, vpiNoDelay); free(text); return 0; }