1 /*
2 * Copyright (c) 2001-2018 Stephen Williams (steve@icarus.com)
3 *
4 * This source code is free software; you can redistribute it
5 * and/or modify it in source code form under the terms of the GNU
6 * General Public License as published by the Free Software
7 * Foundation; either version 2 of the License, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 # include "config.h"
21 # include "vpi_priv.h"
22 # include "schedule.h"
23 # include <cstdio>
24 # include <cmath>
25 # include <cassert>
26
27 /*
28 * The $time system function is supported in VPI contexts (i.e. an
29 * argument to a system task/function) as a vpiSysFuncCall object. The
30 * $display function divines that this is a function call and uses a
31 * vpi_get_value to get the value.
32 */
33
34 /*
35 * vpi_time_precision is the precision of the simulation clock. It is
36 * set by the :vpi_time_precision directive in the vvp source file.
37 */
38 static int vpi_time_precision = 0;
39
40 static struct __vpiSystemTime global_simtime;
41
vpip_time_to_timestruct(struct t_vpi_time * ts,vvp_time64_t ti)42 void vpip_time_to_timestruct(struct t_vpi_time*ts, vvp_time64_t ti)
43 {
44 ts->low = ti & 0xFFFFFFFF;
45 ts->high = (ti >> 32) & 0xFFFFFFFF;
46 }
47
vpip_timestruct_to_time(const struct t_vpi_time * ts)48 vvp_time64_t vpip_timestruct_to_time(const struct t_vpi_time*ts)
49 {
50 vvp_time64_t ti = ts->high;
51 ti <<= 32;
52 ti += ts->low & 0xffffffff;
53 return ti;
54 }
55
vpip_time_to_scaled_real(vvp_time64_t ti,__vpiScope * scope)56 double vpip_time_to_scaled_real(vvp_time64_t ti, __vpiScope*scope)
57 {
58 double val;
59 int scale = 0;
60 if (scope) scale = vpi_time_precision - scope->time_units;
61
62 if (scale >= 0) val = (double)ti * pow(10.0, scale);
63 else val = (double)ti / pow(10.0, -scale);
64
65 return val;
66 }
67
68 /*
69 * This routine does not currently support negative real delays and it
70 * does not check for overflow. It is only used for modpath delays and
71 * they are required to be non-negative.
72 */
vpip_scaled_real_to_time64(double val,__vpiScope * scope)73 vvp_time64_t vpip_scaled_real_to_time64(double val, __vpiScope*scope)
74 {
75 int shift = 0;
76 if (scope) shift = scope->time_units - scope->time_precision;
77 assert(shift >= 0);
78
79 assert(val >= 0);
80
81 // Scale to the local precision and then round away from zero.
82 double scale = pow(10.0L, shift);
83 val *= scale;
84
85 vvp_time64_t delay = (vvp_time64_t) (val + 0.5);
86
87 // If needed now scale the value to the simulator precision.
88 if (scope) {
89 shift = scope->time_precision - vpi_time_precision;
90 assert(shift >= 0);
91 for (int lp = 0; lp < shift; lp += 1) delay *= 10;
92 }
93
94 return delay;
95 }
96
timevar_get_value(vpiHandle ref,s_vpi_value * vp,bool is_int_func,bool is_stime)97 static void timevar_get_value(vpiHandle ref, s_vpi_value*vp, bool is_int_func,
98 bool is_stime)
99 {
100 /* Keep a persistent structure for passing time values back to
101 the caller. */
102 static struct t_vpi_time time_value;
103
104 struct __vpiSystemTime*rfp = dynamic_cast<__vpiSystemTime*>(ref);
105 unsigned long num_bits;
106 vvp_time64_t x, simtime = schedule_simtime();
107 int units = rfp->scope? rfp->scope->time_units : vpi_time_precision;
108
109 char*rbuf = (char *) need_result_buf(128, RBUF_VAL);
110
111 /* Calculate the divisor needed to scale the simulation time
112 (in time_precision units) to time units of the scope. */
113 vvp_time64_t divisor = 1;
114 while (units > vpi_time_precision) {
115 divisor *= 10;
116 units -= 1;
117 }
118
119 /* Scale the simtime, and use the modulus to round up if
120 appropriate. */
121 vvp_time64_t simtime_fraction = simtime % divisor;
122 simtime /= divisor;
123
124 if ((divisor >= 10) && (simtime_fraction >= (divisor/2)))
125 simtime += 1;
126
127 /* If this is a call to $stime only return the lower 32 bits. */
128 if (is_stime) simtime &= 0xffffffff;
129
130 switch (vp->format) {
131 case vpiObjTypeVal:
132 /* The default format is vpiTimeVal. */
133 vp->format = vpiTimeVal;
134 // fallthrough
135 case vpiTimeVal:
136 vp->value.time = &time_value;
137 vp->value.time->type = vpiSimTime;
138 vpip_time_to_timestruct(vp->value.time, simtime);
139 break;
140
141 case vpiRealVal:
142 /* If this is an integer based call (anything but $realtime)
143 * just return the value as a double. */
144 if (is_int_func) vp->value.real = double (simtime);
145 /* This is a call to $realtime to return a real value so
146 * scale this using the scaled real rules. */
147 else vp->value.real = vpip_time_to_scaled_real(schedule_simtime(),
148 rfp->scope);
149 break;
150
151 case vpiBinStrVal:
152 x = simtime;
153 num_bits = 8 * sizeof(vvp_time64_t);
154
155 rbuf[num_bits] = 0;
156 for (unsigned i = 1; i <= num_bits; i++) {
157 rbuf[num_bits-i] = (x & 1) ? '1' : '0';
158 x = x >> 1;
159 }
160
161 vp->value.str = rbuf;
162 break;
163
164 case vpiDecStrVal:
165 sprintf(rbuf, "%" TIME_FMT_U, simtime);
166 vp->value.str = rbuf;
167 break;
168
169 case vpiOctStrVal:
170 sprintf(rbuf, "%" TIME_FMT_O, simtime);
171 vp->value.str = rbuf;
172 break;
173
174 case vpiHexStrVal:
175 sprintf(rbuf, "%" TIME_FMT_X, simtime);
176 vp->value.str = rbuf;
177 break;
178
179 default:
180 fprintf(stderr, "vpi_time: unknown format: %d\n", (int)vp->format);
181 assert(0);
182 }
183 }
184
timevar_get_ivalue(vpiHandle ref,s_vpi_value * vp)185 static void timevar_get_ivalue(vpiHandle ref, s_vpi_value*vp)
186 {
187 timevar_get_value(ref, vp, true, false);
188 }
189
timevar_get_svalue(vpiHandle ref,s_vpi_value * vp)190 static void timevar_get_svalue(vpiHandle ref, s_vpi_value*vp)
191 {
192 timevar_get_value(ref, vp, true, true);
193 }
194
timevar_get_rvalue(vpiHandle ref,s_vpi_value * vp)195 static void timevar_get_rvalue(vpiHandle ref, s_vpi_value*vp)
196 {
197 timevar_get_value(ref, vp, false, false);
198 }
199
__vpiScopedTime()200 __vpiScopedTime::__vpiScopedTime()
201 { }
202
vpi_get_str(int code)203 char* __vpiScopedTime::vpi_get_str(int code)
204 {
205 switch (code) {
206 case vpiName:
207 return simple_set_rbuf_str("$time");
208 default:
209 fprintf(stderr, "Code: %d\n", code);
210 assert(0);
211 return 0;
212 }
213 }
214
215
vpi_get_value(p_vpi_value val)216 void __vpiScopedTime::vpi_get_value(p_vpi_value val)
217 { timevar_get_ivalue(this, val); }
218
219
__vpiScopedSTime()220 __vpiScopedSTime::__vpiScopedSTime()
221 { }
222
vpi_get(int code)223 int __vpiScopedSTime::vpi_get(int code)
224 {
225 switch (code) {
226 case vpiSize:
227 return 32;
228
229 default:
230 return __vpiSystemTime::vpi_get(code);
231 }
232 }
233
234
vpi_get_str(int code)235 char* __vpiScopedSTime::vpi_get_str(int code)
236 {
237 switch (code) {
238 case vpiName:
239 return simple_set_rbuf_str("$stime");
240 default:
241 fprintf(stderr, "Code: %d\n", code);
242 assert(0);
243 return 0;
244 }
245 }
246
247
vpi_get_value(p_vpi_value val)248 void __vpiScopedSTime::vpi_get_value(p_vpi_value val)
249 { timevar_get_svalue(this, val); }
250
__vpiSystemTime()251 __vpiSystemTime::__vpiSystemTime()
252 {
253 scope = 0;
254 }
255
get_type_code(void) const256 int __vpiSystemTime::get_type_code(void) const
257 { return vpiSysFuncCall; }
258
vpi_get(int code)259 int __vpiSystemTime::vpi_get(int code)
260 {
261 switch (code) {
262 case vpiSize:
263 return 64;
264
265 case vpiSigned:
266 return 0;
267
268 case vpiFuncType:
269 return vpiTimeFunc;
270
271 case vpiAutomatic:
272 return 0;
273
274 default:
275 fprintf(stderr, "Code: %d\n", code);
276 assert(0);
277 return 0;
278 }
279 }
280
281
vpi_get_str(int code)282 char* __vpiSystemTime::vpi_get_str(int code)
283 {
284 switch (code) {
285 case vpiName:
286 return simple_set_rbuf_str("$simtime");
287 default:
288 fprintf(stderr, "Code: %d\n", code);
289 assert(0);
290 return 0;
291 }
292 }
293
294
vpi_get_value(p_vpi_value val)295 void __vpiSystemTime::vpi_get_value(p_vpi_value val)
296 { timevar_get_ivalue(this, val); }
297
vpi_handle(int code)298 vpiHandle __vpiSystemTime::vpi_handle(int code)
299 {
300 switch (code) {
301 case vpiScope:
302 return scope;
303 default:
304 return 0;
305 }
306 }
307
308
__vpiScopedRealtime()309 __vpiScopedRealtime::__vpiScopedRealtime()
310 { }
311
vpi_get(int code)312 int __vpiScopedRealtime::vpi_get(int code)
313 {
314 switch (code) {
315 case vpiSize:
316 return 1;
317
318 case vpiSigned:
319 return 0;
320
321 case vpiFuncType:
322 return vpiRealFunc;
323
324 case vpiAutomatic:
325 return 0;
326
327 default:
328 fprintf(stderr, "Code: %d\n", code);
329 assert(0);
330 return 0;
331 }
332 }
333
334
vpi_get_str(int code)335 char* __vpiScopedRealtime::vpi_get_str(int code)
336 {
337 switch (code) {
338 case vpiName:
339 return simple_set_rbuf_str("$realtime");
340 default:
341 fprintf(stderr, "Code: %d\n", code);
342 assert(0);
343 return 0;
344 }
345 }
346
347
vpi_get_value(p_vpi_value val)348 void __vpiScopedRealtime::vpi_get_value(p_vpi_value val)
349 { timevar_get_rvalue(this, val); }
350
351 /*
352 * Create a handle to represent a call to $time/$stime/$simtime. The
353 * $time and $stime system functions return a value scaled to a scope,
354 * and the $simtime returns the unscaled time.
355 */
vpip_sim_time(__vpiScope * scope,bool is_stime)356 vpiHandle vpip_sim_time(__vpiScope*scope, bool is_stime)
357 {
358 if (scope) {
359 if (is_stime) {
360 scope->scoped_stime.scope = scope;
361 return &scope->scoped_stime;
362 } else {
363 scope->scoped_time.scope = scope;
364 return &scope->scoped_time;
365 }
366 } else {
367 return &global_simtime;
368 }
369 }
370
vpip_sim_realtime(__vpiScope * scope)371 vpiHandle vpip_sim_realtime(__vpiScope*scope)
372 {
373 scope->scoped_realtime.scope = scope;
374 return &scope->scoped_realtime;
375 }
376
vpip_get_time_precision(void)377 int vpip_get_time_precision(void)
378 {
379 return vpi_time_precision;
380 }
381
vpip_set_time_precision(int pre)382 void vpip_set_time_precision(int pre)
383 {
384 vpi_time_precision = pre;
385 }
386