1 /*
2  * Copyright (c) 2001-2018 Stephen Williams (steve@icarus.com)
3  * Copyright (c) 2001 Stephan Boettcher <stephan@nevis.columbia.edu>
4  *
5  *    This source code is free software; you can redistribute it
6  *    and/or modify it in source code form under the terms of the GNU
7  *    General Public License as published by the Free Software
8  *    Foundation; either version 2 of the License, or (at your option)
9  *    any later version.
10  *
11  *    This program is distributed in the hope that it will be useful,
12  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *    GNU General Public License for more details.
15  *
16  *    You should have received a copy of the GNU General Public License
17  *    along with this program; if not, write to the Free Software
18  *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  */
20 
21 /*
22  * vpiReg handles are handled here. These objects represent vectors of
23  * .var objects that can be manipulated by the VPI module.
24  */
25 
26 # include  "vpi_priv.h"
27 # include  "vthread.h"
28 # include  "config.h"
29 #ifdef CHECK_WITH_VALGRIND
30 # include  "vvp_cleanup.h"
31 # include <map>
32 #endif
33 # include  <cstdio>
34 # include  <cstdlib>
35 # include  <cassert>
36 # include  "ivl_alloc.h"
37 
38 /*
39  * Hex digits that represent 4-value bits of Verilog are not as
40  * trivially obvious to display as if the bits were the usual 2-value
41  * bits. So, although it is possible to write a function that
42  * generates a correct character for 4*4-value bits, it is easier to
43  * just perform the lookup in a table. This only takes 256 bytes,
44  * which is not many executable instructions:-)
45  *
46  * The table is calculated as compile time, therefore, by the
47  * draw_tt.c program.
48  */
49 extern const char hex_digits[256];
50 extern const char oct_digits[64];
51 
52 
53 struct __vpiVThrWord : public __vpiHandle {
54       __vpiVThrWord();
55       int get_type_code(void) const;
56       int vpi_get(int code);
57       void vpi_get_value(p_vpi_value val);
58 
59       const char* name;
60       int subtype;
61       unsigned index;
62 };
63 
vthr_word_get(int code,vpiHandle ref)64 static int vthr_word_get(int code, vpiHandle ref)
65 {
66       struct __vpiVThrWord*rfp = dynamic_cast<__vpiVThrWord*>(ref);
67 
68       switch (code) {
69 
70 	  case vpiConstType:
71 	    return rfp->subtype;
72 
73 #if defined(CHECK_WITH_VALGRIND) || defined(BR916_STOPGAP_FIX)
74 	  case _vpiFromThr:
75 	    return _vpiWord;
76 #endif
77 
78 	  default:
79 	    return 0;
80       }
81 }
82 
vlg_round(double rval)83 static double vlg_round(double rval)
84 {
85       if (rval >= 0.0) {
86             return floor(rval + 0.5);
87       } else {
88             return ceil(rval - 0.5);
89       }
90 }
91 
vthr_real_get_value(vpiHandle ref,s_vpi_value * vp)92 static void vthr_real_get_value(vpiHandle ref, s_vpi_value*vp)
93 {
94       struct __vpiVThrWord*obj = dynamic_cast<__vpiVThrWord*>(ref);
95       char *rbuf = (char *) need_result_buf(66, RBUF_VAL);
96 
97       double val = 0.0;
98 
99 	/* Get the actual value from the index. It is possible, by the
100 	   way, that the vpi_get_value is called from compiletf. If
101 	   that's the case, there will be no current thread, and this
102 	   will not have access to the proper value. Punt and return a
103 	   0.0 value instead. */
104       if (vpip_current_vthread)
105 	    val = vthread_get_real_stack(vpip_current_vthread, obj->index);
106 
107       switch (vp->format) {
108 
109 	  case vpiObjTypeVal:
110 	    vp->format = vpiRealVal;
111 	    // fallthrough
112 	  case vpiRealVal:
113 	    vp->value.real = val;
114 	    break;
115 
116 	  case vpiIntVal:
117 	      /* NaN or +/- infinity are translated as 0. */
118 	    if (val != val || (val && (val == 0.5*val))) {
119 		  val = 0.0;
120 	    } else {
121 		  val = vlg_round(val);
122 	    }
123 	    vp->value.integer = (PLI_INT32)val;
124 	    break;
125 
126 	  case vpiDecStrVal:
127 	    if (isnan(val))
128 		  sprintf(rbuf, "%s", "nan");
129 	    else
130 		  sprintf(rbuf, "%0.0f", vlg_round(val));
131 	    vp->value.str = rbuf;
132 	    break;
133 
134 	  case vpiOctStrVal:
135 	    sprintf(rbuf, "%" PRIo64, (uint64_t)vlg_round(val));
136 	    vp->value.str = rbuf;
137 	    break;
138 
139 	  case vpiHexStrVal:
140 	    sprintf(rbuf, "%" PRIx64, (uint64_t)vlg_round(val));
141 	    vp->value.str = rbuf;
142 	    break;
143 
144 	  case vpiBinStrVal: {
145 		uint64_t vali = (uint64_t)vlg_round(val);
146 		unsigned len = 0;
147 
148 		while (vali > 0) {
149 		      len += 1;
150 		      vali /= 2;
151 		}
152 
153 		vali = (uint64_t)vlg_round(val);
154 		for (unsigned idx = 0 ;  idx < len ;  idx += 1) {
155 		      rbuf[len-idx-1] = (vali & 1)? '1' : '0';
156 		      vali /= 2;
157 		}
158 
159 		rbuf[len] = 0;
160 		if (len == 0) {
161 		      rbuf[0] = '0';
162 		      rbuf[1] = 0;
163 		}
164 		vp->value.str = rbuf;
165 		break;
166 	  }
167 
168 	  default:
169 	    fprintf(stderr, "vvp error: get %d not supported "
170 		      "by vpiConstant (Real)\n", (int)vp->format);
171 
172 	    vp->format = vpiSuppressVal;
173 	    break;
174       }
175 }
176 
__vpiVThrWord()177 inline __vpiVThrWord::__vpiVThrWord()
178 { }
179 
get_type_code(void) const180 int __vpiVThrWord::get_type_code(void) const
181 { return vpiConstant; }
182 
vpi_get(int code)183 int __vpiVThrWord::vpi_get(int code)
184 { return vthr_word_get(code, this); }
185 
vpi_get_value(p_vpi_value val)186 void __vpiVThrWord::vpi_get_value(p_vpi_value val)
187 { vthr_real_get_value(this, val); }
188 
vpip_make_vthr_word(unsigned base,const char * type)189 vpiHandle vpip_make_vthr_word(unsigned base, const char*type)
190 {
191       struct __vpiVThrWord*obj = new __vpiVThrWord;
192 
193       assert(type[0] == 'r');
194 
195       obj->name = vpip_name_string("W<>");
196       obj->subtype = vpiRealConst;
197       assert(base < 65536);
198       obj->index = base;
199 
200       return obj;
201 }
202 
203 #ifdef CHECK_WITH_VALGRIND
204 static map<vpiHandle, bool> handle_map;
205 
thread_word_delete(vpiHandle item)206 void thread_word_delete(vpiHandle item)
207 {
208       handle_map[item] = false;
209 }
210 
thread_word_delete_real(vpiHandle item)211 static void thread_word_delete_real(vpiHandle item)
212 {
213       struct __vpiVThrWord*obj = dynamic_cast<__vpiVThrWord*>(item);
214       delete obj;
215 }
216 #endif
217 
218 class __vpiVThrStrStack : public __vpiHandle {
219     public:
220       explicit __vpiVThrStrStack(unsigned depth);
221       int get_type_code(void) const;
222       int vpi_get(int code);
223       void vpi_get_value(p_vpi_value val);
224     private:
225       unsigned depth_;
226 };
227 
__vpiVThrStrStack(unsigned d)228 __vpiVThrStrStack::__vpiVThrStrStack(unsigned d)
229 : depth_(d)
230 {
231 }
232 
get_type_code(void) const233 int __vpiVThrStrStack::get_type_code(void) const
234 { return vpiConstant; }
235 
vpi_get(int code)236 int __vpiVThrStrStack::vpi_get(int code)
237 {
238       switch (code) {
239 	  case vpiConstType:
240 	    return vpiStringConst;
241 #if defined(CHECK_WITH_VALGRIND) || defined(BR916_STOPGAP_FIX)
242 	  case _vpiFromThr:
243 	    return _vpiString;
244 #endif
245 	  default:
246 	    return 0;
247       }
248 }
249 
vpi_get_value(p_vpi_value vp)250 void __vpiVThrStrStack::vpi_get_value(p_vpi_value vp)
251 {
252       string val;
253       char*rbuf = 0;
254 
255       if (vpip_current_vthread)
256 	    val = vthread_get_str_stack(vpip_current_vthread, depth_);
257 
258       switch (vp->format) {
259 
260 	  case vpiObjTypeVal:
261 	    vp->format = vpiStringVal;
262 	    // fallthrough
263 	  case vpiStringVal:
264 	    rbuf = (char *) need_result_buf(val.size()+1, RBUF_VAL);
265 	    strcpy(rbuf, val.c_str());
266 	    vp->value.str = rbuf;
267 	    break;
268 
269 	  default:
270 	    fprintf(stderr, "vvp error: get %d not supported "
271 		      "by vpiConstant (String)\n", (int)vp->format);
272 
273 	    vp->format = vpiSuppressVal;
274 	    break;
275       }
276 }
277 
278 class __vpiVThrVec4Stack : public __vpiHandle {
279     public:
280       __vpiVThrVec4Stack(unsigned depth, bool signed_flag, unsigned wid);
281       int get_type_code(void) const;
282       int vpi_get(int code);
283       char*vpi_get_str(int code);
284       void vpi_get_value(p_vpi_value val);
285       vpiHandle vpi_put_value(p_vpi_value val, int flags);
286     private:
287       void vpi_get_value_string_(p_vpi_value vp, const vvp_vector4_t&val);
288       void vpi_get_value_binstr_(p_vpi_value vp, const vvp_vector4_t&val);
289       void vpi_get_value_decstr_(p_vpi_value vp, const vvp_vector4_t&val);
290       void vpi_get_value_int_   (p_vpi_value vp, const vvp_vector4_t&val);
291       void vpi_get_value_real_  (p_vpi_value vp, const vvp_vector4_t&val);
292       void vpi_get_value_strength_(p_vpi_value vp, const vvp_vector4_t&val);
293       void vpi_get_value_octstr_(p_vpi_value vp, const vvp_vector4_t&val);
294       void vpi_get_value_hexstr_(p_vpi_value vp, const vvp_vector4_t&val);
295       void vpi_get_value_vector_(p_vpi_value vp, const vvp_vector4_t&val);
296     private:
297       unsigned depth_;
298       bool signed_flag_;
299       unsigned expect_width_;
300       const char*name;
301 };
302 
__vpiVThrVec4Stack(unsigned d,bool sf,unsigned wid)303 __vpiVThrVec4Stack::__vpiVThrVec4Stack(unsigned d, bool sf, unsigned wid)
304 : depth_(d), signed_flag_(sf), expect_width_(wid)
305 {
306       name = vpip_name_string("S<,vec4,>");
307 }
308 
get_type_code(void) const309 int __vpiVThrVec4Stack::get_type_code(void) const
310 { return vpiConstant; }
311 
312 
vpi_get(int code)313 int __vpiVThrVec4Stack::vpi_get(int code)
314 {
315       switch (code) {
316 	  case vpiSize:
317 	    return expect_width_;
318 
319 	  case vpiSigned:
320 	    return signed_flag_? 1 : 0;
321 
322 	  case vpiConstType:
323 	    return vpiBinaryConst;
324 
325 #if defined(CHECK_WITH_VALGRIND) || defined(BR916_STOPGAP_FIX)
326 	  case _vpiFromThr:
327 	    return _vpiVThr;
328 #endif
329 
330 	  default:
331 	    return 0;
332       }
333 }
334 
vpi_get_str(int code)335 char*__vpiVThrVec4Stack::vpi_get_str(int code)
336 {
337       switch (code) {
338 	  case vpiFullName:
339 	    return simple_set_rbuf_str(name);
340 
341 	  default:
342 	    return 0;
343       }
344 }
345 
vpi_get_value(p_vpi_value vp)346 void __vpiVThrVec4Stack::vpi_get_value(p_vpi_value vp)
347 {
348       vvp_vector4_t val;
349 
350       if (vpip_current_vthread)
351 	    val = vthread_get_vec4_stack(vpip_current_vthread, depth_);
352 
353       switch (vp->format) {
354 
355 	  case vpiBinStrVal:
356 	    vpi_get_value_binstr_(vp, val);
357 	    break;
358 	  case vpiDecStrVal:
359 	    vpi_get_value_decstr_(vp, val);
360 	    break;
361 	  case vpiOctStrVal:
362 	    vpi_get_value_octstr_(vp, val);
363 	    break;
364 	  case vpiHexStrVal:
365 	    vpi_get_value_hexstr_(vp, val);
366 	    break;
367 	  case vpiIntVal:
368 	    vpi_get_value_int_(vp, val);
369 	    break;
370 	  case vpiRealVal:
371 	    vpi_get_value_real_(vp, val);
372 	    break;
373 	  case vpiStringVal:
374 	    vpi_get_value_string_(vp, val);
375 	    break;
376 	  case vpiStrengthVal:
377 	    vpi_get_value_strength_(vp, val);
378 	    break;
379 	  case vpiObjTypeVal:
380 	    vp->format = vpiVectorVal;
381 	    // fallthrough
382 	  case vpiVectorVal:
383 	    vpi_get_value_vector_(vp, val);
384 	    break;
385 
386 	  default:
387 	    fprintf(stderr, "internal error: vpi_get_value(<format=%d>)"
388 		    " not implemented for __vpiVThrVec4Stack.\n", vp->format);
389 	    assert(0);
390       }
391 
392 }
393 
vpi_get_value_binstr_(p_vpi_value vp,const vvp_vector4_t & val)394 void __vpiVThrVec4Stack::vpi_get_value_binstr_(p_vpi_value vp, const vvp_vector4_t&val)
395 {
396       unsigned wid = val.size();
397       char*rbuf = (char*) need_result_buf(wid+1, RBUF_VAL);
398       for (unsigned idx = 0 ; idx < wid ; idx += 1) {
399 	    rbuf[wid-idx-1] = vvp_bit4_to_ascii(val.value(idx));
400       }
401       rbuf[wid] = 0;
402       vp->value.str = rbuf;
403 }
404 
vpi_get_value_decstr_(p_vpi_value vp,const vvp_vector4_t & val)405 void __vpiVThrVec4Stack::vpi_get_value_decstr_(p_vpi_value vp, const vvp_vector4_t&val)
406 {
407       unsigned wid = val.size();
408       int nbuf = (wid+2)/3 + 1;
409       char *rbuf = (char*) need_result_buf(nbuf, RBUF_VAL);
410 
411       vpip_vec4_to_dec_str(val, rbuf, nbuf, signed_flag_);
412       vp->value.str = rbuf;
413 }
414 
vpi_get_value_octstr_(p_vpi_value vp,const vvp_vector4_t & val)415 void __vpiVThrVec4Stack::vpi_get_value_octstr_(p_vpi_value vp, const vvp_vector4_t&val)
416 {
417       unsigned wid = val.size();
418       unsigned owid = (wid + 2) / 3;
419       char*rbuf = (char*) need_result_buf(owid+1, RBUF_VAL);
420       rbuf[owid] = 0;
421 
422       unsigned oval = 0;
423       for (unsigned idx = 0; idx < wid ; idx += 1) {
424 	    unsigned tmp = 0;
425 	    switch (val.value(idx)) {
426 		case BIT4_0:
427 		  tmp = 0;
428 		  break;
429 		case BIT4_1:
430 		  tmp = 1;
431 		  break;
432 		case BIT4_X:
433 		  tmp = 2;
434 		  break;
435 		case BIT4_Z:
436 		  tmp = 3;
437 		  break;
438 	    }
439 
440 	    oval = oval | (tmp << 2*(idx%3));
441 
442 	    if (idx%3 == 2) {
443 		  owid -= 1;
444 		  rbuf[owid] = oct_digits[oval];
445 		  oval = 0;
446 	    }
447       }
448 
449       if (owid > 0) {
450 	    owid -= 1;
451 	    rbuf[owid] = oct_digits[oval];
452 	    oval = 0;
453       }
454       vp->value.str = rbuf;
455 }
456 
vpi_get_value_hexstr_(p_vpi_value vp,const vvp_vector4_t & val)457 void __vpiVThrVec4Stack::vpi_get_value_hexstr_(p_vpi_value vp, const vvp_vector4_t&val)
458 {
459       unsigned wid = val.size();
460       unsigned hwid = (wid + 3) /4;
461       char*rbuf = (char*) need_result_buf(hwid+1, RBUF_VAL);
462       rbuf[hwid] = 0;
463 
464       unsigned hval = 0;
465       for (unsigned idx = 0; idx < wid ; idx += 1) {
466 	    unsigned tmp = 0;
467 	    switch (val.value(idx)) {
468 		case BIT4_0:
469 		  tmp = 0;
470 		  break;
471 		case BIT4_1:
472 		  tmp = 1;
473 		  break;
474 		case BIT4_X:
475 		  tmp = 2;
476 		  break;
477 		case BIT4_Z:
478 		  tmp = 3;
479 		  break;
480 	    }
481 	    hval = hval | (tmp << 2*(idx%4));
482 
483 	    if (idx%4 == 3) {
484 		  hwid -= 1;
485 		  rbuf[hwid] = hex_digits[hval];
486 		  hval = 0;
487 	    }
488       }
489 
490       if (hwid > 0) {
491 	    hwid -= 1;
492 	    rbuf[hwid] = hex_digits[hval];
493 	    hval = 0;
494       }
495       vp->value.str = rbuf;
496 }
497 
vpi_get_value_int_(p_vpi_value vp,const vvp_vector4_t & val)498 void __vpiVThrVec4Stack::vpi_get_value_int_(p_vpi_value vp, const vvp_vector4_t&val)
499 {
500       int32_t vali = 0;
501       vector4_to_value(val, vali, signed_flag_, false);
502       vp->value.integer = vali;
503 }
504 
vpi_get_value_real_(p_vpi_value vp,const vvp_vector4_t & val)505 void __vpiVThrVec4Stack::vpi_get_value_real_(p_vpi_value vp, const vvp_vector4_t&val)
506 {
507       unsigned wid = val.size();
508       vp->value.real = 0.0;
509 
510       for (unsigned idx = wid ; idx > 0 ; idx -= 1) {
511 	    vp->value.real *= 2.0;
512 	    if (val.value(idx-1) == BIT4_1)
513 		  vp->value.real += 1.0;
514       }
515 }
516 
vpi_get_value_string_(p_vpi_value vp,const vvp_vector4_t & val)517 void __vpiVThrVec4Stack::vpi_get_value_string_(p_vpi_value vp, const vvp_vector4_t&val)
518 {
519       char*rbuf = (char*) need_result_buf((val.size() / 8) + 1, RBUF_VAL);
520       char*cp = rbuf;
521 
522       char tmp = 0;
523       for (int bitnr = val.size()-1 ; bitnr >= 0 ; bitnr -= 1) {
524 	    tmp <<= 1;
525 	    switch (val.value(bitnr)) {
526 		case BIT4_1:
527 		  tmp |= 1;
528 		  break;
529 		case BIT4_0:
530 		default:
531 		  break;
532 	    }
533 
534 	    if ((bitnr&7)==0) {
535 		    // Don't include leading nuls
536 		  if (tmp == 0 && cp == rbuf)
537 			continue;
538 
539 		  *cp++ = tmp? tmp : ' ';
540 		  tmp = 0;
541 	    }
542       }
543       *cp++ = 0;
544       vp->format = vpiStringVal;
545       vp->value.str = rbuf;
546 }
547 
vpi_get_value_vector_(p_vpi_value vp,const vvp_vector4_t & val)548 void __vpiVThrVec4Stack::vpi_get_value_vector_(p_vpi_value vp, const vvp_vector4_t&val)
549 {
550       unsigned wid = val.size();
551 
552       vp->value.vector = (s_vpi_vecval*)
553 	    need_result_buf((wid+31)/32*sizeof(s_vpi_vecval), RBUF_VAL);
554       assert(vp->value.vector);
555 
556       for (unsigned idx = 0 ;  idx < wid ;  idx += 1) {
557 	    int word = idx/32;
558 	    PLI_INT32 mask = 1 << (idx%32);
559 
560 	    switch (val.value(idx)) {
561 		case BIT4_0:
562 		  vp->value.vector[word].aval &= ~mask;
563 		  vp->value.vector[word].bval &= ~mask;
564 		  break;
565 		case BIT4_1:
566 		  vp->value.vector[word].aval |=  mask;
567 		  vp->value.vector[word].bval &= ~mask;
568 		  break;
569 		case BIT4_X:
570 		  vp->value.vector[word].aval |=  mask;
571 		  vp->value.vector[word].bval |=  mask;
572 		  break;
573 		case BIT4_Z:
574 		  vp->value.vector[word].aval &= ~mask;
575 		  vp->value.vector[word].bval |=  mask;
576 		  break;
577 	    }
578       }
579 }
580 
vpi_get_value_strength_(p_vpi_value vp,const vvp_vector4_t & val)581 void __vpiVThrVec4Stack::vpi_get_value_strength_(p_vpi_value vp, const vvp_vector4_t&val)
582 {
583       s_vpi_strengthval*op = (s_vpi_strengthval*)
584 	    need_result_buf(val.size() * sizeof(s_vpi_strengthval), RBUF_VAL);
585 
586       for (unsigned idx = 0 ; idx < val.size() ; idx += 1) {
587 	    switch (val.value(idx)) {
588 		case BIT4_0:
589 		  op[idx].logic = vpi0;
590 		  op[idx].s0 = vpiStrongDrive;
591 		  op[idx].s1 = 0;
592 		  break;
593 		case BIT4_1:
594 		  op[idx].logic = vpi1;
595 		  op[idx].s0 = 0;
596 		  op[idx].s1 = vpiStrongDrive;
597 		  break;
598 		case BIT4_X:
599 		  op[idx].logic = vpiX;
600 		  op[idx].s0 = vpiStrongDrive;
601 		  op[idx].s1 = vpiStrongDrive;
602 		  break;
603 		case BIT4_Z:
604 		  op[idx].logic = vpiZ;
605 		  op[idx].s0 = vpiHiZ;
606 		  op[idx].s1 = vpiHiZ;
607 		  break;
608 	    }
609       }
610 
611       vp->format = vpiStrengthVal;
612       vp->value.strength = op;
613 }
614 
vpi_put_value(p_vpi_value vp,int)615 vpiHandle __vpiVThrVec4Stack::vpi_put_value(p_vpi_value vp, int /*flags*/)
616 {
617       assert(vpip_current_vthread);
618 
619       switch (vp->format) {
620 
621 	  default:
622 	    fprintf(stderr, "internal error: vpi_put_value(<format=%d>)"
623 		    " not implemented for __vpiVThrVec4Stack.\n", vp->format);
624 	    assert(0);
625 	    return 0;
626       }
627 }
628 
629 #ifdef CHECK_WITH_VALGRIND
thread_vthr_delete(vpiHandle item)630 void thread_vthr_delete(vpiHandle item)
631 {
632       handle_map[item] = true;
633 }
634 
thread_vthr_delete_real(vpiHandle item)635 static void thread_vthr_delete_real(vpiHandle item)
636 {
637       __vpiVThrVec4Stack*obj = dynamic_cast<__vpiVThrVec4Stack*>(item);
638       delete obj;
639 }
640 
vpi_handle_delete()641 void vpi_handle_delete()
642 {
643       map<vpiHandle, bool>::iterator iter;
644       for (iter = handle_map.begin(); iter != handle_map.end(); ++ iter ) {
645 	    if (iter->second) thread_vthr_delete_real(iter->first);
646 	    else thread_word_delete_real(iter->first);
647       }
648 }
649 #endif
650 
651 
vpip_make_vthr_str_stack(unsigned depth)652 vpiHandle vpip_make_vthr_str_stack(unsigned depth)
653 {
654       __vpiVThrStrStack*obj = new __vpiVThrStrStack(depth);
655       return obj;
656 }
657 
vpip_make_vthr_vec4_stack(unsigned depth,bool signed_flag,unsigned wid)658 vpiHandle vpip_make_vthr_vec4_stack(unsigned depth, bool signed_flag, unsigned wid)
659 {
660       __vpiVThrVec4Stack*obj = new __vpiVThrVec4Stack(depth, signed_flag, wid);
661       return obj;
662 }
663 
664 #ifdef CHECK_WITH_VALGRIND
665 static map<vpiHandle, bool> stack_map;
666 
thread_string_delete(vpiHandle item)667 void thread_string_delete(vpiHandle item)
668 {
669       stack_map[item] = false;
670 }
671 
thread_string_delete_real(vpiHandle item)672 static void thread_string_delete_real(vpiHandle item)
673 {
674       __vpiVThrStrStack*obj = dynamic_cast<__vpiVThrStrStack*>(item);
675       delete obj;
676 }
677 
vpi_stack_delete()678 void vpi_stack_delete()
679 {
680       map<vpiHandle, bool>::iterator iter;
681       for (iter = stack_map.begin(); iter != stack_map.end(); ++ iter ) {
682 	    thread_string_delete_real(iter->first);
683       }
684 }
685 #endif
686