static PLI_INT32 sys_convert_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 an argument. */ if (argv == 0) { error_message(callh, "%s requires one argument.\n"); return 0; } /* In Icarus if we have an argv we have at least one argument. */ arg = vpi_scan(argv); /* Validate the argument. Only $bitstoreal for now. */ if (!strcmp("$bitstoreal", name) && vpi_get(vpiSize, arg) != 64) { error_message(callh, "%s requires a 64-bit argument.\n"); return 0; } /* Save the argument away to make the calltf faster. */ vpi_put_userdata(callh, (void *) arg); /* These functions only take one argument. */ check_for_extra_args(argv, callh, name, "one argument", 0); return 0; }
static int sys_random_calltf(char*name) { s_vpi_value val; vpiHandle call_handle; vpiHandle argv; vpiHandle seed = 0; int i_seed = 0; struct context_s *context; call_handle = vpi_handle(vpiSysTfCall, 0); assert(call_handle); /* Get the argument list and look for a seed. If it is there, get the value and reseed the random number generator. */ argv = vpi_iterate(vpiArgument, call_handle); if (argv) { seed = vpi_scan(argv); vpi_free_object(argv); val.format = vpiIntVal; vpi_get_value(seed, &val); i_seed = val.value.integer; /* Since there is a seed use the current context or create a new one */ context = (struct context_s *)vpi_get_userdata(call_handle); if (!context) { context = (struct context_s *)calloc(1, sizeof(*context)); context->mti = NP1; assert(context); /* squrrel away context */ vpi_put_userdata(call_handle, (void *)context); } /* If the argument is not the Icarus cookie, then reseed context */ if (i_seed != COOKIE) sgenrand(context, i_seed); } else { /* use global context */ context = &global_context; } val.format = vpiIntVal; val.value.integer = genrand(context); vpi_put_value(call_handle, &val, 0, vpiNoDelay); /* mark seed with cookie */ if (seed && i_seed != COOKIE) { val.format = vpiIntVal; val.value.integer = COOKIE; vpi_put_value(seed, &val, 0, vpiNoDelay); } return 0; }
static PLI_INT32 ivlh_attribute_event_compiletf(ICARUS_VPI_CONST PLI_BYTE8*data) { event_type_t type = (event_type_t) data; vpiHandle sys = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, sys); vpiHandle arg; struct monitor_data*mon; struct t_cb_data cb; struct t_vpi_time tb; struct t_vpi_value vb; /* Check that there are arguments. */ if (argv == 0) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys), (int)vpi_get(vpiLineNo, sys)); vpi_printf("(compiler error) %s requires a single argument.\n", func_names[type]); vpi_control(vpiFinish, 1); return 0; } /* Icarus either returns 0 above or has one argument. */ arg = vpi_scan(argv); assert(arg); mon = malloc(sizeof(struct monitor_data)); /* Add this to the list of data. */ mdata_count += 1; mdata = (struct monitor_data **) realloc(mdata, sizeof(struct monitor_data **) * mdata_count); mdata[mdata_count-1] = mon; tb.type = vpiSimTime; vb.format = vpiScalarVal; cb.reason = cbValueChange; cb.cb_rtn = monitor_events; cb.obj = arg; cb.time = &tb; cb.value = &vb; cb.user_data = (char*) (mon); vpi_register_cb(&cb); vpi_put_userdata(sys, mon); /* Check that there is no more than one argument. */ arg = vpi_scan(argv); if (arg != 0) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys), (int)vpi_get(vpiLineNo, sys)); vpi_printf("(compiler error) %s only takes a single argument.\n", func_names[type]); vpi_free_object(argv); vpi_control(vpiFinish, 1); } return 0; }
/* * Routine to check all the double argument math functions. */ static PLI_INT32 va_double_argument_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *ud) { vpiHandle callh, argv, arg; const t_double_data *data; const char *name; va_double_t* fun_data; assert(ud != 0); callh = vpi_handle(vpiSysTfCall, 0); assert(callh != 0); argv = vpi_iterate(vpiArgument, callh); data = (const t_double_data *) ud; name = data->name; fun_data = malloc(sizeof(va_double_t)); /* Check that there are arguments. */ if (argv == 0) { va_error_message(callh, "%s requires two arguments.\n", name); free(fun_data); return 0; } /* In Icarus if we have an argv we have at least one argument. */ arg = vpi_scan(argv); fun_data->arg1 = va_process_argument(callh, name, arg, " (arg1)"); /* Check that there are at least two arguments. */ arg = vpi_scan(argv); if (arg == 0) { va_error_message(callh, "%s requires two arguments.\n", name); } fun_data->arg2 = va_process_argument(callh, name, arg, " (arg2)"); /* These functions only take two arguments. */ arg = vpi_scan(argv); if (arg != 0) { va_error_message(callh, "%s takes only two arguments.\n", name); vpi_free_object(argv); } /* Get the function that is to be used by the calltf routine. */ fun_data->func = data->func; vpi_put_userdata(callh, fun_data); double_funcs_count += 1; double_funcs = (va_double_t **)realloc(double_funcs, double_funcs_count*sizeof(va_double_t **)); double_funcs[double_funcs_count-1] = fun_data; /* vpi_scan() returning 0 (NULL) has already freed argv. */ return 0; }
static PLI_INT32 sys_mti_random_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle callh, argv, seed = 0; s_vpi_value val; int i_seed = COOKIE; struct context_s *context; (void)name; /* Parameter is not used. */ /* Get the argument list and look for a seed. If it is there, get the value and reseed the random number generator. */ callh = vpi_handle(vpiSysTfCall, 0); argv = vpi_iterate(vpiArgument, callh); val.format = vpiIntVal; if (argv) { seed = vpi_scan(argv); vpi_free_object(argv); vpi_get_value(seed, &val); i_seed = val.value.integer; /* Since there is a seed use the current context or create a new one */ context = (struct context_s *)vpi_get_userdata(callh); if (!context) { context = (struct context_s *)calloc(1, sizeof(*context)); context->mti = NP1; /* squirrel away context */ vpi_put_userdata(callh, (void *)context); } /* If the argument is not the Icarus cookie, then reseed context */ if (i_seed != COOKIE) sgenrand(context, i_seed); } else { /* use global context */ context = &global_context; } /* Calculate and return the result */ val.value.integer = genrand(context); vpi_put_value(callh, &val, 0, vpiNoDelay); /* mark seed with cookie */ if (seed && i_seed != COOKIE) { val.value.integer = COOKIE; vpi_put_value(seed, &val, 0, vpiNoDelay); } 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; }
/* * This function calls the veriusertfs checktf and sets up all the * callbacks misctf requires. */ static PLI_INT32 compiletf(char *data) { p_pli_data pli; p_tfcell tf; s_cb_data cb_data; vpiHandle call_h, arg_i, arg_h; p_pli_data dp; int rtn = 0; /* cast back from opaque */ pli = (p_pli_data)data; tf = pli->tf; /* get call handle */ call_h = vpi_handle(vpiSysTfCall, NULL); /* Attach the pli_data structure to the vpi handle of the system task. This is how I manage the map from vpiHandle to PLI1 pli data. We do it here (instead of during register) because this is the first that I have both the vpiHandle and the pli_data. */ vpi_put_userdata(call_h, pli); /* default cb_data */ memset(&cb_data, 0, sizeof(s_cb_data)); cb_data.cb_rtn = callback; cb_data.user_data = data; /* register EOS misctf callback */ cb_data.reason = cbEndOfSimulation; cb_data.obj = call_h; vpi_register_cb(&cb_data); /* If there is a misctf function, then create a value change callback for all the arguments. In the tf_* API, misctf functions get value change callbacks, controlled by the tf_asyncon and tf_asyncoff functions. */ if (tf->misctf && ((arg_i = vpi_iterate(vpiArgument, call_h)) != NULL)) { int paramvc = 1; cb_data.reason = cbValueChange; while ((arg_h = vpi_scan(arg_i)) != NULL) { /* replicate user_data for each instance */ dp = calloc(1, sizeof(s_pli_data)); memcpy(dp, cb_data.user_data, sizeof(s_pli_data)); dp->paramvc = paramvc++; cb_data.user_data = (char *)dp; cb_data.obj = arg_h; vpi_register_cb(&cb_data); } } /* * Since we are in compiletf, checktf and misctf need to * be executed. Check runs first to match other simulators. */ if (tf->checktf) { if (pli_trace) { fprintf(pli_trace, "Call %s->checktf(reason_checktf)\n", tf->tfname); } rtn = tf->checktf(tf->data, reason_checktf); } if (tf->misctf) { if (pli_trace) { fprintf(pli_trace, "Call %s->misctf" "(user_data=%d, reason=%d, paramvc=%d)\n", tf->tfname, tf->data, reason_endofcompile, 0); } tf->misctf(tf->data, reason_endofcompile, 0); } return rtn; }