/* This also supports $abstime() from VAMS-2.3. */ static PLI_INT32 sys_realtime_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { s_vpi_value val; s_vpi_time now; vpiHandle callh; vpiHandle mod; callh = vpi_handle(vpiSysTfCall, 0); assert(callh); mod = sys_func_module(callh); now.type = vpiScaledRealTime; vpi_get_time(mod, &now); /* For $abstime() we return the time in second. */ if (strcmp(name, "$abstime") == 0) { PLI_INT32 scale = vpi_get(vpiTimeUnit, mod); if (scale >= 0) now.real *= pow(10.0, scale); else now.real /= pow(10.0, -scale); } val.format = vpiRealVal; val.value.real = now.real; vpi_put_value(callh, &val, 0, vpiNoDelay); return 0; }
static PLI_INT32 sys_dumpall_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { s_vpi_time now; PLI_UINT64 now64; (void)name; /* Parameter is not used. */ if (dump_is_off) return 0; if (dump_file == 0) return 0; if (dump_header_pending()) return 0; now.type = vpiSimTime; vpi_get_time(0, &now); now64 = timerec_to_time64(&now); if (now64 > vcd_cur_time) { fprintf(dump_file, "#%" PLI_UINT64_FMT "\n", now64); vcd_cur_time = now64; } fprintf(dump_file, "$dumpall\n"); vcd_checkpoint(); fprintf(dump_file, "$end\n"); return 0; }
static PLI_INT32 sys_dumpon_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { s_vpi_time now; PLI_UINT64 now64; (void)name; /* Parameter is not used. */ if (!dump_is_off) return 0; dump_is_off = 0; if (dump_file == 0) return 0; if (dump_header_pending()) return 0; now.type = vpiSimTime; vpi_get_time(0, &now); now64 = timerec_to_time64(&now); if (now64 > vcd_cur_time) { vcd_work_set_time(now64); vcd_cur_time = now64; } vcd_work_dumpon(); vcd_checkpoint(); return 0; }
static PLI_INT32 sys_dumpon_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { s_vpi_time now; PLI_UINT64 now64; if (!dump_is_off) return 0; dump_is_off = 0; if (dump_file == 0) return 0; if (dump_header_pending()) return 0; now.type = vpiSimTime; vpi_get_time(0, &now); now64 = timerec_to_time64(&now); if (now64 > vcd_cur_time) { fstWriterEmitTimeChange(dump_file, now64); vcd_cur_time = now64; } fstWriterEmitDumpActive(dump_file, 1); /* $dumpon */ vcd_checkpoint(); return 0; }
static PLI_INT32 from_myhdl_calltf(PLI_BYTE8 *user_data) { vpiHandle reg_iter, reg_handle; s_vpi_time verilog_time_s; char buf[MAXLINE]; char s[MAXWIDTH]; int n; static int from_myhdl_flag = 0; if (from_myhdl_flag) { vpi_printf("ERROR: $from_myhdl called more than once\n"); vpi_control(vpiFinish, 1); /* abort simulation */ return(0); } from_myhdl_flag = 1; init_pipes(); verilog_time_s.type = vpiSimTime; vpi_get_time(NULL, &verilog_time_s); verilog_time = timestruct_to_time(&verilog_time_s); if (verilog_time != 0) { vpi_printf("ERROR: $from_myhdl should be called at time 0\n"); vpi_control(vpiFinish, 1); /* abort simulation */ return(0); } sprintf(buf, "FROM 0 "); pli_time = 0; delta = 0; from_myhdl_systf_handle = vpi_handle(vpiSysTfCall, NULL); reg_iter = vpi_iterate(vpiArgument, from_myhdl_systf_handle); while ((reg_handle = vpi_scan(reg_iter)) != NULL) { if (vpi_get(vpiType, reg_handle) != vpiReg) { vpi_printf("ERROR: $from_myhdl argument %s should be a reg\n", vpi_get_str(vpiName, reg_handle)); vpi_control(vpiFinish, 1); /* abort simulation */ return(0); } strcat(buf, vpi_get_str(vpiName, reg_handle)); strcat(buf, " "); sprintf(s, "%d ", vpi_get(vpiSize, reg_handle)); strcat(buf, s); vpi_free_object(reg_handle); } //vpi_free_object(reg_iter); n = write(wpipe, buf, strlen(buf)); if ((n = read(rpipe, buf, MAXLINE)) == 0) { vpi_printf("Info: MyHDL simulator down\n"); vpi_control(vpiFinish, 1); /* abort simulation */ return(0); } assert(n > 0); buf[n] = '\0'; return(0); }
static PLI_INT32 sys_dumpon_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { s_vpi_time now; PLI_UINT64 now64; if (!dump_is_off) return 0; dump_is_off = 0; if (dump_file == 0) return 0; if (dump_header_pending()) return 0; now.type = vpiSimTime; vpi_get_time(0, &now); now64 = timerec_to_time64(&now); if (now64 > vcd_cur_time) { lt_set_time64(dump_file, now64); vcd_cur_time = now64; } lt_set_dumpon(dump_file); vcd_checkpoint(); return 0; }
static PLI_INT32 sys_dumpall_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { s_vpi_time now; PLI_UINT64 now64; (void)name; /* Parameter is not used. */ if (dump_is_off) return 0; if (dump_file == 0) return 0; if (dump_header_pending()) return 0; now.type = vpiSimTime; vpi_get_time(0, &now); now64 = timerec_to_time64(&now); if (now64 > vcd_cur_time) { fstWriterEmitTimeChange(dump_file, now64); vcd_cur_time = now64; } /* nothing to do for $dumpall... */ vcd_checkpoint(); return 0; }
void update_time(void) { s_vpi_time time_s; vpiHandle sys = vpi_handle(vpiSysTfCall, 0); time_s.type = vpiScaledRealTime; vpi_get_time(sys, &time_s); g_time = time_s.real; }
void VpiImpl::get_sim_time(uint32_t *high, uint32_t *low) { s_vpi_time vpi_time_s; vpi_time_s.type = vpiSimTime; //vpiSimTime; vpi_get_time(NULL, &vpi_time_s); check_vpi_error(); *high = vpi_time_s.high; *low = vpi_time_s.low; }
static PLI_INT32 sys_time_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { s_vpi_value val; s_vpi_time now; vpiHandle call_handle; vpiHandle mod; int units, prec; long scale; call_handle = vpi_handle(vpiSysTfCall, 0); assert(call_handle); mod = sys_func_module(call_handle); now.type = vpiSimTime; vpi_get_time(0, &now); /* All the variants but $simtime return the time in units of the local scope. The $simtime function returns the simulation time. */ if (strcmp(name, "$simtime") == 0) units = vpi_get(vpiTimePrecision, 0); else units = vpi_get(vpiTimeUnit, mod); prec = vpi_get(vpiTimePrecision, 0); scale = 1; while (units > prec) { scale *= 10; units -= 1; } assert(8*sizeof(long long) >= 64); { long frac; long long tmp_now = ((long long)now.high) << 32; tmp_now += (long long)now.low; frac = tmp_now % (long long)scale; tmp_now /= (long long)scale; /* Round to the nearest integer, which may be up. */ if ((scale > 1) && (frac >= scale/2)) tmp_now += 1; now.low = tmp_now & 0xffffffff; now.high = tmp_now >> 32LL; } val.format = vpiTimeVal; val.value.time = &now; vpi_put_value(call_handle, &val, 0, vpiNoDelay); return 0; }
PLI_INT32 ValueChange(p_cb_data cb_data) { static s_vpi_time get_time = { vpiSimTime, 0, 0, 0 }; (void)cb_data; /* Parameter is not used. */ vpi_get_time(NULL,&get_time); vpi_printf("%6d: Value Change\n", (int)get_time.low); return(0); }
static long long get_time() { s_vpi_time time; time.type = vpiSimTime; vpi_get_time(NULL, &time); uint64_t long_time; long_time = time.high; long_time <<= 32; long_time += time.low; return (long long)long_time; }
static PLI_INT32 next_sim_time_callback(struct t_cb_data*cb) { vpiHandle obj = (vpiHandle)cb->user_data; s_vpi_value val; s_vpi_time tim; val.format = vpiIntVal; vpi_get_value(obj, &val); tim.type = vpiSimTime; vpi_get_time(obj, &tim); vpi_printf("Callback time=%d %s=%d\n", (int)tim.low, vpi_get_str(vpiName, obj), (int)val.value.integer); return 0; }
static PLI_INT32 Callback(s_cb_data *data) { s_vpi_time t; static int count = 0; t.type = vpiScaledRealTime; vpi_get_time(0, &t); vpi_printf("Callback @ %.1f\n", t.real); if (count>1) { vpi_printf("vpi_remove_cb returned %d @ %.1f\n", (int)vpi_remove_cb(Handle), t.real); } count++; return 0; }
static PLI_INT32 ivlh_attribute_event_calltf(ICARUS_VPI_CONST PLI_BYTE8*data) { event_type_t type = (event_type_t) data; vpiHandle sys = vpi_handle(vpiSysTfCall, 0); struct t_vpi_value rval; struct monitor_data*mon; rval.format = vpiScalarVal; mon = (struct monitor_data*) (vpi_get_userdata(sys)); if (mon->last_event.type == 0) { rval.value.scalar = vpi0; } else { struct t_vpi_time tnow; tnow.type = vpiSimTime; vpi_get_time(0, &tnow); rval.value.scalar = vpi1; // Detect if change occured in this moment if (mon->last_event.high != tnow.high) rval.value.scalar = vpi0; if (mon->last_event.low != tnow.low) rval.value.scalar = vpi0; // Determine the edge, if required if (type == RISING_EDGE && mon->last_value.value.scalar != vpi1) rval.value.scalar = vpi0; else if (type == FALLING_EDGE && mon->last_value.value.scalar != vpi0) rval.value.scalar = vpi0; } vpi_put_value(sys, &rval, 0, vpiNoDelay); return 0; }
static PLI_INT32 to_myhdl_calltf(PLI_BYTE8 *user_data) { vpiHandle net_iter, net_handle, cb_h; char buf[MAXLINE]; char s[MAXWIDTH]; int n; int i; int *id; s_cb_data cb_data_s; s_vpi_time verilog_time_s; s_vpi_time time_s; s_vpi_value value_s; static int to_myhdl_flag = 0; if (to_myhdl_flag) { vpi_printf("ERROR: $to_myhdl called more than once\n"); vpi_control(vpiFinish, 1); /* abort simulation */ return(0); } to_myhdl_flag = 1; init_pipes(); verilog_time_s.type = vpiSimTime; vpi_get_time(NULL, &verilog_time_s); verilog_time = timestruct_to_time(&verilog_time_s); if (verilog_time != 0) { vpi_printf("ERROR: $to_myhdl should be called at time 0\n"); vpi_control(vpiFinish, 1); /* abort simulation */ return(0); } sprintf(buf, "TO 0 "); pli_time = 0; delta = 0; time_s.type = vpiSuppressTime; value_s.format = vpiSuppressVal; cb_data_s.reason = cbValueChange; cb_data_s.cb_rtn = change_callback; cb_data_s.time = &time_s; cb_data_s.value = &value_s; // value_s.format = vpiHexStrVal; i = 0; to_myhdl_systf_handle = vpi_handle(vpiSysTfCall, NULL); net_iter = vpi_iterate(vpiArgument, to_myhdl_systf_handle); while ((net_handle = vpi_scan(net_iter)) != NULL) { if (i == MAXARGS) { vpi_printf("ERROR: $to_myhdl max #args (%d) exceeded\n", MAXARGS); vpi_control(vpiFinish, 1); /* abort simulation */ } strcat(buf, vpi_get_str(vpiName, net_handle)); strcat(buf, " "); sprintf(s, "%d ", vpi_get(vpiSize, net_handle)); strcat(buf, s); changeFlag[i] = 0; id = malloc(sizeof(int)); *id = i; cb_data_s.user_data = (PLI_BYTE8 *)id; cb_data_s.obj = net_handle; cb_h = vpi_register_cb(&cb_data_s); vpi_free_object(cb_h); i++; vpi_free_object(net_handle); } //vpi_free_object(net_iter); n = write(wpipe, buf, strlen(buf)); if ((n = read(rpipe, buf, MAXLINE)) == 0) { vpi_printf("ABORT from $to_myhdl\n"); vpi_control(vpiFinish, 1); /* abort simulation */ return(0); } buf[n] = '\0'; assert(n > 0); // register read-only callback // time_s.type = vpiSimTime; time_s.high = 0; time_s.low = 0; cb_data_s.reason = cbReadOnlySynch; cb_data_s.user_data = NULL; cb_data_s.cb_rtn = readonly_callback; cb_data_s.obj = NULL; cb_data_s.time = &time_s; cb_data_s.value = NULL; cb_h = vpi_register_cb(&cb_data_s); vpi_free_object(cb_h); // pre-register delta cycle callback // delta = 0; time_s.type = vpiSimTime; time_s.high = 0; time_s.low = 1; cb_data_s.reason = cbAfterDelay; cb_data_s.user_data = NULL; cb_data_s.cb_rtn = delta_callback; cb_data_s.obj = NULL; cb_data_s.time = &time_s; cb_data_s.value = NULL; cb_h = vpi_register_cb(&cb_data_s); vpi_free_object(cb_h); return(0); }
static PLI_INT32 readonly_callback(p_cb_data cb_data) { vpiHandle net_iter, net_handle, cb_h; s_cb_data cb_data_s; s_vpi_time verilog_time_s; s_vpi_value value_s; s_vpi_time time_s; char buf[MAXLINE]; int n; int i; char *myhdl_time_string; myhdl_time64_t delay; static int start_flag = 1; if (start_flag) { start_flag = 0; n = write(wpipe, "START", 5); // vpi_printf("INFO: RO cb at start-up\n"); if ((n = read(rpipe, buf, MAXLINE)) == 0) { vpi_printf("ABORT from RO cb at start-up\n"); vpi_control(vpiFinish, 1); /* abort simulation */ } assert(n > 0); } buf[0] = '\0'; verilog_time_s.type = vpiSimTime; vpi_get_time(NULL, &verilog_time_s); verilog_time = timestruct_to_time(&verilog_time_s); if (verilog_time != (pli_time * 1000 + delta)) { vpi_printf("%u %u\n", verilog_time_s.high, verilog_time_s.low ); vpi_printf("%llu %llu %d\n", verilog_time, pli_time, delta); } /* Icarus 0.7 fails on this assertion beyond 32 bits due to a bug */ // assert(verilog_time == pli_time * 1000 + delta); assert( (verilog_time & 0xFFFFFFFF) == ( (pli_time * 1000 + delta) & 0xFFFFFFFF ) ); sprintf(buf, "%llu ", pli_time); net_iter = vpi_iterate(vpiArgument, to_myhdl_systf_handle); value_s.format = vpiHexStrVal; i = 0; while ((net_handle = vpi_scan(net_iter)) != NULL) { if (changeFlag[i]) { strcat(buf, vpi_get_str(vpiName, net_handle)); strcat(buf, " "); vpi_get_value(net_handle, &value_s); strcat(buf, value_s.value.str); strcat(buf, " "); changeFlag[i] = 0; } i++; vpi_free_object(net_handle); // done with this one } //vpi_free_object(net_iter); n = write(wpipe, buf, strlen(buf)); if ((n = read(rpipe, buf, MAXLINE)) == 0) { // vpi_printf("ABORT from RO cb\n"); vpi_control(vpiFinish, 1); /* abort simulation */ return(0); } assert(n > 0); buf[n] = '\0'; /* save copy for later callback */ strcpy(bufcp, buf); myhdl_time_string = strtok(buf, " "); myhdl_time = (myhdl_time64_t) strtoull(myhdl_time_string, (char **) NULL, 10); delay = (myhdl_time - pli_time) * 1000; assert(delay >= 0); assert(delay <= 0xFFFFFFFF); if (delay > 0) { // schedule cbAfterDelay callback assert(delay > delta); delay -= delta; /* Icarus 20030518 runs RO callbacks when time has already advanced */ /* Therefore, one had to compensate for the prescheduled delta callback */ /* delay -= 1; */ /* Icarus 20031009 has a different scheduler, more correct I believe */ /* compensation is no longer necessary */ delta = 0; pli_time = myhdl_time; // register cbAfterDelay callback // time_s.type = vpiSimTime; time_s.high = 0; time_s.low = (PLI_UINT32) delay; cb_data_s.reason = cbAfterDelay; cb_data_s.user_data = NULL; cb_data_s.cb_rtn = delay_callback; cb_data_s.obj = NULL; cb_data_s.time = &time_s; cb_data_s.value = NULL; cb_h = vpi_register_cb(&cb_data_s); vpi_free_object(cb_h); } else { delta++; assert(delta < 1000); } return(0); }
/* * This is a VPI callback that notices the value change. This function * further dispatches the information about the callback to the * consumer function. */ static PLI_INT32 vcl_value_callback(struct t_cb_data*cb) { s_vpi_time sim_time; s_vpi_value obj_value; struct t_vc_record vcr; struct vcl_record*cur = (struct vcl_record*)cb->user_data; sim_time.type = vpiSimTime; vpi_get_time(cur->obj, &sim_time); switch (cur->vcl_flag) { case VCL_VERILOG_LOGIC: vpi_printf("XXXX vcl_value_callback(%s=%d);\n", vpi_get_str(vpiName, cur->obj), -1); vcr.vc_reason = logic_value_change; break; case VCL_VERILOG_STRENGTH: vcr.vc_reason = strength_value_change; obj_value.format = vpiStrengthVal; vpi_get_value(cur->obj, &obj_value); assert(obj_value.format == vpiStrengthVal); switch (obj_value.value.strength[0].logic) { case vpi0: vcr.out_value.strengths_s.logic_value = acc0; vcr.out_value.strengths_s.strength1 = vpi_strength_to_vcl(obj_value.value.strength[0].s0); vcr.out_value.strengths_s.strength2 = vpi_strength_to_vcl(obj_value.value.strength[0].s0); break; case vpi1: vcr.out_value.strengths_s.logic_value = acc1; vcr.out_value.strengths_s.strength1 = vpi_strength_to_vcl(obj_value.value.strength[0].s1); vcr.out_value.strengths_s.strength2 = vpi_strength_to_vcl(obj_value.value.strength[0].s1); break; case vpiX: vcr.out_value.strengths_s.logic_value = accX; vcr.out_value.strengths_s.strength1 = vpi_strength_to_vcl(obj_value.value.strength[0].s1); vcr.out_value.strengths_s.strength2 = vpi_strength_to_vcl(obj_value.value.strength[0].s0); break; case vpiZ: vcr.out_value.strengths_s.logic_value = accZ; vcr.out_value.strengths_s.strength1 = vclHighZ; vcr.out_value.strengths_s.strength2 = vclHighZ; break; default: assert(0); } if (pli_trace) { fprintf(pli_trace, "Call vcl_value_callback(%s=%d <s1=%d,s2=%d>)\n", vpi_get_str(vpiFullName, cur->obj), vcr.out_value.strengths_s.logic_value, vcr.out_value.strengths_s.strength1, vcr.out_value.strengths_s.strength2); } break; default: assert(0); } vcr.vc_hightime = sim_time.high; vcr.vc_lowtime = sim_time.low; vcr.user_data = cur->user_data; (cur->consumer) (&vcr); return 0; }
static PLI_INT32 simbus_ready_calltf(char*my_name) { s_vpi_value value; s_vpi_time now; vpiHandle sys = vpi_handle(vpiSysTfCall, 0); /* vpiHandle scope = vpi_handle(vpiScope, sys); */ vpiHandle argv = vpi_iterate(vpiArgument, sys); vpiHandle arg; assert(argv); arg = vpi_scan(argv); assert(arg); /* Get the BUS identifier to use. */ value.format = vpiIntVal; vpi_get_value(arg, &value); int bus_id = value.value.integer; assert(bus_id < MAX_INSTANCES); assert(instance_table[bus_id].fd >= 0); DEBUG(SIMBUS_DEBUG_CALLS, "Call $ready(%d...)\n", bus_id); /* Get the simulation time. */ now.type = vpiSimTime; vpi_get_time(0, &now); uint64_t now_int = ((uint64_t)now.high) << 32; now_int += (uint64_t) now.low; /* Get the units for the simulation. */ int scale = vpi_get(vpiTimePrecision, 0); /* Minimize the mantissa by increasing the scale so long as the mantissa is a multiple of 10. This is not a functional requirement, but it does help prevent a runaway precision expansion. */ while (now_int >= 10 && (now_int%10 == 0)) { now_int /= 10; scale += 1; } char message[MAX_MESSAGE+1]; snprintf(message, sizeof message, "READY %" PRIu64 "e%d", now_int, scale); char*cp = message + strlen(message); /* Send the current state of all the named signals. The format passed in to the argument list is "name", value. Write these values in the proper message format. */ for (arg = vpi_scan(argv) ; arg ; arg = vpi_scan(argv)) { *cp++ = ' '; value.format = vpiStringVal; vpi_get_value(arg, &value); strcpy(cp, value.value.str); cp += strlen(cp); *cp++ = '='; vpiHandle sig = vpi_scan(argv); assert(sig); value.format = vpiVectorVal; vpi_get_value(sig, &value); int bit; char*sig_string = cp; for (bit = vpi_get(vpiSize, sig) ; bit > 0 ; bit -= 1) { int word = (bit-1) / 32; int mask = 1 << ((bit-1) % 32); if (value.value.vector[word].aval & mask) if (value.value.vector[word].bval & mask) *cp++ = 'x'; else *cp++ = '1'; else if (value.value.vector[word].bval & mask) *cp++ = 'z'; else *cp++ = '0'; } /* The second value after the signal name is the drive reference. It is the value that the server is driving (or 'bz if this is output-only). Look at the driver value, and if it is non-z and equal to the value that I see in the verilog, then assume that this is the driver driving the value and subtract it. */ vpiHandle drv = vpi_scan(argv); assert(drv); assert(vpi_get(vpiSize,drv) == vpi_get(vpiSize,sig)); value.format = vpiVectorVal; vpi_get_value(drv, &value); char*drv_reference = malloc(vpi_get(vpiSize,drv)); for (bit = vpi_get(vpiSize,drv) ; bit > 0 ; bit -= 1) { int word = (bit-1) / 32; int mask = 1 << ((bit-1) % 32); if (value.value.vector[word].aval & mask) if (value.value.vector[word].bval & mask) drv_reference[bit-1] = 'x'; else drv_reference[bit-1] = '1'; else if (value.value.vector[word].bval & mask) drv_reference[bit-1] = 'z'; else drv_reference[bit-1] = '0'; } /* Get the strength values from the signal. */ value.format = vpiStrengthVal; vpi_get_value(sig, &value); /* Now given the sig_string that is the current result, and the drive reference that is the value that is being driven by the server, subtract out from the sig_string the server driver, and any pullups from the port. */ for (bit = vpi_get(vpiSize,drv); bit > 0; bit -= 1, sig_string+=1) { if (drv_reference[bit-1] == *sig_string) { *sig_string = 'z'; continue; } if (*sig_string == 'z') continue; if (*sig_string == 'x') continue; /* Do not pass pullup/pulldown values to the server. If the strength of the net is less then a strong drive, then clear it to z. */ struct t_vpi_strengthval*str = value.value.strength + bit - 1; if (str->s0 < vpiStrongDrive && str->s1 < vpiStrongDrive) *sig_string = 'z'; } free(drv_reference); assert(sig_string == cp); } *cp++ = '\n'; *cp = 0; DEBUG(SIMBUS_DEBUG_PROTOCOL, "Send %s", message); int rc = write(instance_table[bus_id].fd, message, strlen(message)); assert(rc == strlen(message)); DEBUG(SIMBUS_DEBUG_CALLS, "Return from $ready(%d...)\n", bus_id); return 0; }
static PLI_INT32 simbus_until_calltf(char*my_name) { s_vpi_time now; s_vpi_value value; vpiHandle sys = vpi_handle(vpiSysTfCall, 0); vpiHandle scope = vpi_handle(vpiScope, sys); vpiHandle argv = vpi_iterate(vpiArgument, sys); vpiHandle bus_h = vpi_scan(argv); assert(bus_h); value.format = vpiIntVal; vpi_get_value(bus_h, &value); int bus = value.value.integer; assert(bus >= 0 && bus < MAX_INSTANCES); DEBUG(SIMBUS_DEBUG_CALLS, "Call $until(%d...)\n", bus); /* Get a list of the signals and their mapping to a handle. We will use list list to map names from the UNTIL command back to the handle. */ struct signal_list_cell*signal_list = 0; vpiHandle key, sig; for (key = vpi_scan(argv) ; key ; key = vpi_scan(argv)) { sig = vpi_scan(argv); assert(sig); struct signal_list_cell*tmp = calloc(1, sizeof(struct signal_list_cell)); value.format = vpiStringVal; vpi_get_value(key, &value); assert(value.format == vpiStringVal); assert(value.value.str); tmp->key = strdup(value.value.str); tmp->sig = sig; tmp->next = signal_list; signal_list = tmp; } /* Now read the command from the server. This will block until the server data actually arrives. */ char buf[MAX_MESSAGE+1]; int rc = read_message(bus, buf, sizeof buf); if (rc <= 0) { vpi_printf("%s:%d: %s() read from server failed\n", vpi_get_str(vpiFile, sys), (int)vpi_get(vpiLineNo, sys), my_name); vpi_control(vpiStop); free_signal_list(signal_list); /* Set the return value and return. */ value.format = vpiIntVal; value.value.integer = 0; vpi_put_value(sys, &value, 0, vpiNoDelay); DEBUG(SIMBUS_DEBUG_CALLS, "Return 0 from $until(%d...)\n", bus); return 0; } DEBUG(SIMBUS_DEBUG_PROTOCOL, "Recv %s\n", buf); /* Chop the message into tokens. */ int msg_argc = 0; char* msg_argv[MAX_MESSAGE/2]; char*cp = buf; while (*cp != 0) { msg_argv[msg_argc++] = cp; cp += strcspn(cp, " "); if (*cp) { *cp++ = 0; cp += strspn(cp, " "); } } msg_argv[msg_argc] = 0; /* If we get a FINISH command from the server, then $finish the local simulation. */ if (strcmp(msg_argv[0],"FINISH") == 0) { vpi_printf("Server disconnected with FINISH command\n"); vpi_control(vpiFinish); free_signal_list(signal_list); /* Set the return value and return. */ value.format = vpiIntVal; value.value.integer = 0; vpi_put_value(sys, &value, 0, vpiNoDelay); DEBUG(SIMBUS_DEBUG_CALLS, "Return 0 from $until(%d...)\n", bus); return 0; } assert(strcmp(msg_argv[0],"UNTIL") == 0); assert(msg_argc >= 2); uint64_t until_mant = strtoull(msg_argv[1],&cp,10); assert(cp && *cp=='e'); cp += 1; int until_exp = strtol(cp,0,0); /* Get the units for the scope */ int units = vpi_get(vpiTimeUnit, scope); /* Put the until time into units of the scope. */ while (units < until_exp) { until_mant *= 10; until_exp -= 1; } while (units > until_exp) { until_mant = (until_mant + 5)/10; until_exp += 1; } /* Get the simulation time and put it into scope units. */ now.type = vpiSimTime; vpi_get_time(0, &now); uint64_t deltatime = ((uint64_t)now.high) << 32; deltatime += (uint64_t) now.low; int prec = vpi_get(vpiTimePrecision, 0); while (prec < units) { prec += 1; deltatime = (until_mant + 5)/10; } /* Now we can calculate the delta time. */ if (deltatime > until_mant) deltatime = 0; else deltatime = until_mant - deltatime; /* Set the return value and return it. */ value.format = vpiIntVal; value.value.integer = deltatime; vpi_put_value(sys, &value, 0, vpiNoDelay); /* Process the signal values. */ int idx; for (idx = 2 ; idx < msg_argc ; idx += 1) { char*mkey = msg_argv[idx]; char*val = strchr(mkey, '='); assert(val && *val=='='); *val++ = 0; struct signal_list_cell*cur = find_key_in_list(signal_list, mkey); if (cur == 0) { vpi_printf("%s:%d: %s() Unexpected signal %s from bus.\n", vpi_get_str(vpiFile, sys), (int)vpi_get(vpiLineNo, sys), my_name, mkey); continue; } set_handle_to_value(cur->sig, val); } free_signal_list(signal_list); DEBUG(SIMBUS_DEBUG_CALLS, "Return %" PRIu64 " from $until(%d...)\n", deltatime, bus); return 0; }