1 /*
2  * Copyright (c) 2007-2013 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  "array_common.h"
21 # include  "array.h"
22 # include  "symbols.h"
23 # include  "schedule.h"
24 # include  "vpi_priv.h"
25 # include  "vvp_net_sig.h"
26 # include  "vvp_darray.h"
27 # include  "config.h"
28 #ifdef CHECK_WITH_VALGRIND
29 #include  "vvp_cleanup.h"
30 #endif
31 # include  <cstdlib>
32 # include  <cstring>
33 # include  <climits>
34 # include  <iostream>
35 # include  "compile.h"
36 # include  <cassert>
37 # include  "ivl_alloc.h"
38 
39 unsigned long count_net_arrays = 0;
40 unsigned long count_net_array_words = 0;
41 unsigned long count_var_arrays = 0;
42 unsigned long count_var_array_words = 0;
43 unsigned long count_real_arrays = 0;
44 unsigned long count_real_array_words = 0;
45 
46 static symbol_map_s<struct __vpiArray>* array_table =0;
47 
48 class vvp_fun_arrayport;
49 static void array_attach_port(vvp_array_t, vvp_fun_arrayport*);
50 
array_find(const char * label)51 vvp_array_t array_find(const char*label)
52 {
53       if (array_table == 0)
54 	    return 0;
55 
56       vvp_array_t v = array_table->sym_get_value(label);
57       return v;
58 }
59 
60 struct __vpiArrayVthrA : public __vpiHandle {
get_type_code__vpiArrayVthrA61       int get_type_code(void) const { return vpiMemoryWord; }
62       int vpi_get(int code);
63       char* vpi_get_str(int code);
64       void vpi_get_value(p_vpi_value val);
65       vpiHandle vpi_put_value(p_vpi_value val, int flags);
66       vpiHandle vpi_handle(int code);
67 
68       struct __vpiArray*array;
69 	// If this is set, then use it to get the index value.
70       vpiHandle address_handle;
71 	// If wid==0, then address is the address into the array.
72       unsigned address;
73 
get_address__vpiArrayVthrA74       unsigned get_address() const
75       {
76 	    if (address_handle) {
77 		  s_vpi_value vp;
78 		    /* Check to see if the value is defined. */
79 		  vp.format = vpiVectorVal;
80 		  address_handle->vpi_get_value(&vp);
81 		  int words = (address_handle->vpi_get(vpiSize)-1)/32 + 1;
82 		  for(int idx = 0; idx < words; idx += 1) {
83 			  /* Return UINT_MAX to indicate an X base. */
84 			if (vp.value.vector[idx].bval != 0) return UINT_MAX;
85 		  }
86 		    /* The value is defined so get and return it. */
87 		  vp.format = vpiIntVal;
88 		  address_handle->vpi_get_value(&vp);
89 		  return vp.value.integer;
90 	    }
91 
92 	    return address;
93       }
94 };
95 
96 
97 struct __vpiArrayVthrAPV : public __vpiHandle {
get_type_code__vpiArrayVthrAPV98       int get_type_code(void) const { return vpiPartSelect; }
99       int vpi_get(int code);
100       char* vpi_get_str(int code);
101       void vpi_get_value(p_vpi_value val);
102       vpiHandle vpi_handle(int code);
103 
104       struct __vpiArray*array;
105       unsigned word_sel;
106       unsigned part_bit;
107       unsigned part_wid;
108 };
109 
is_net_array(vpiHandle obj)110 bool is_net_array(vpiHandle obj)
111 {
112       struct __vpiArray*rfp = dynamic_cast<__vpiArray*> (obj);
113       assert(rfp);
114 
115       if (rfp->nets != 0) return true;
116       return false;
117 }
118 
119 // This function return true if the underlying array words are real.
vpi_array_is_real(const vvp_array_t arr)120 static bool vpi_array_is_real(const vvp_array_t arr)
121 {
122 	// Check to see if this is a variable/register array.
123       if (arr->vals4 != 0)  // A bit based variable/register array.
124 	    return false;
125 
126       if (dynamic_cast<vvp_darray_real*> (arr->vals))
127 	    return true;
128 
129       if (arr->vals != 0)
130 	    return false;
131 
132 	// This must be a net array so look at element 0 to find the type.
133       assert(arr->nets != 0);
134       assert(arr->get_size() > 0);
135       struct __vpiRealVar*rsig = dynamic_cast<__vpiRealVar*>(arr->nets[0]);
136       if (rsig) {
137 	    return true;
138       }
139 
140       return false;
141 }
142 
vpi_array_is_string(const vvp_array_t arr)143 static bool vpi_array_is_string(const vvp_array_t arr)
144 {
145 	// Check to see if this is a variable/register array.
146       if (arr->vals4 != 0)  // A bit based variable/register array.
147 	    return false;
148 
149       if (dynamic_cast<vvp_darray_string*> (arr->vals))
150 	    return true;
151 
152       return false;
153 }
154 
get_word_size() const155 int __vpiArray::get_word_size() const
156 {
157       unsigned width;
158 
159       assert(get_size() > 0);
160 	/* For a net array we need to get the width from the first element. */
161       if (nets) {
162 	    assert(vals4 == 0 && vals == 0);
163 	    struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(nets[0]);
164 	    assert(vsig);
165 	    width = vpip_size(vsig);
166 	/* For a variable array we can get the width from vals_width. */
167       } else {
168 	    assert(vals4 || vals);
169 	    width = vals_width;
170       }
171 
172       return width;
173 }
174 
get_word_str(struct __vpiArrayWord * word,int code)175 char*__vpiArray::get_word_str(struct __vpiArrayWord*word, int code)
176 {
177       unsigned index = word->get_index();
178 
179       if (code == vpiFile) {  // Not implemented for now!
180 	    return simple_set_rbuf_str(file_names[0]);
181       }
182 
183       char sidx [64];
184       snprintf(sidx, 63, "%d", (int)index + first_addr.get_value());
185       return generic_get_str(code, get_scope(), name, sidx);
186 }
187 
get_word_value(struct __vpiArrayWord * word,p_vpi_value vp)188 void __vpiArray::get_word_value(struct __vpiArrayWord*word, p_vpi_value vp)
189 {
190       unsigned index = word->get_index();
191 
192     // Determine the appropriate format (The Verilog PLI Handbook 5.2.10)
193       if(vp->format == vpiObjTypeVal) {
194           if(vpi_array_is_real(this))
195               vp->format = vpiRealVal;
196           else if(vpi_array_is_string(this))
197               vp->format = vpiStringVal;
198           else
199               vp->format = vpiIntVal;
200       }
201 
202       if(vals4) {
203           vpip_vec4_get_value(vals4->get_word(index),
204                               vals4->width(), signed_flag, vp);
205       } else if(vals) {
206           switch(vp->format) {
207             case vpiBinStrVal:
208             case vpiOctStrVal:
209             case vpiDecStrVal:
210             case vpiHexStrVal:
211             case vpiScalarVal:
212             case vpiIntVal:
213             {
214                 vvp_vector4_t v;
215                 vals->get_word(index, v);
216                 vpip_vec4_get_value(v, vals_width, signed_flag, vp);
217             }
218             break;
219 
220             case vpiVectorVal:
221             {
222                 vvp_vector4_t v;
223                 vals->get_word(index, v);
224                 vpip_vec2_get_value(v, vals_width, signed_flag, vp);
225             }
226             break;
227 
228             case vpiRealVal:
229             {
230                 double d;
231                 vals->get_word(index, d);
232                 vpip_real_get_value(d, vp);
233             }
234             break;
235 
236             case vpiStringVal:
237             {
238                 string s;
239                 vals->get_word(index, s);
240                 vpip_string_get_value(s, vp);
241             }
242             break;
243 
244             default:
245                 fprintf(stderr, "vpi sorry: format is not implemented\n");
246                 assert(false);
247           }
248       }
249 }
250 
put_word_value(struct __vpiArrayWord * word,p_vpi_value vp,int)251 void __vpiArray::put_word_value(struct __vpiArrayWord*word, p_vpi_value vp, int)
252 {
253       unsigned index = word->get_index();
254       vvp_vector4_t val = vec4_from_vpi_value(vp, vals_width);
255       set_word(index, 0, val);
256 }
257 
get_iter_index(struct __vpiArrayIterator *,int idx)258 vpiHandle __vpiArray::get_iter_index(struct __vpiArrayIterator*, int idx)
259 {
260       if (nets) return nets[idx];
261 
262       assert(vals4 || vals);
263 
264       if (vals_words == 0) make_vals_words();
265 
266       return &(vals_words[idx].as_word);
267 }
268 
vpi_get(int code)269 int __vpiArray::vpi_get(int code)
270 {
271       switch (code) {
272 	  case vpiLineNo:
273 	    return 0; // Not implemented for now!
274 
275 	  case vpiSize:
276 	    return get_size();
277 
278 	  case vpiAutomatic:
279 	    return scope->is_automatic()? 1 : 0;
280 
281 	  default:
282 	    return 0;
283       }
284 }
285 
vpi_get_str(int code)286 char* __vpiArray::vpi_get_str(int code)
287 {
288       if (code == vpiFile) {  // Not implemented for now!
289             return simple_set_rbuf_str(file_names[0]);
290       }
291 
292       return generic_get_str(code, scope, name, NULL);
293 }
294 
vpi_handle(int code)295 vpiHandle __vpiArray::vpi_handle(int code)
296 {
297       switch (code) {
298           case vpiLeftRange:
299             if (swap_addr) return &last_addr;
300             else return &first_addr;
301 
302           case vpiRightRange:
303             if (swap_addr) return &first_addr;
304             else return &last_addr;
305 
306 	  case vpiScope:
307 	    return scope;
308 
309 	  case vpiModule:
310 	    return vpip_module(scope);
311       }
312 
313       return 0;
314 }
315 
316 /*
317 * VPI code passes indices that are not yet converted to canonical
318 * form, so this index function does it here.
319 */
vpi_index(int index)320 vpiHandle __vpiArray::vpi_index(int index)
321 {
322       index -= first_addr.get_value();
323       if (index >= (long) get_size())
324 	    return 0;
325       if (index < 0)
326 	    return 0;
327 
328       if (nets != 0) {
329 	    return nets[index];
330       }
331 
332       if (vals_words == 0)
333 	    make_vals_words();
334 
335       return &(vals_words[index].as_word);
336 }
337 
vpi_get(int code)338 int __vpiArrayWord::as_word_t::vpi_get(int code)
339 {
340       struct __vpiArrayWord*obj = array_var_word_from_handle(this);
341       assert(obj);
342       struct __vpiArrayBase*parent = obj->get_parent();
343       t_vpi_value val;
344 
345       switch (code) {
346 	  case vpiLineNo:
347 	    return 0; // Not implemented for now!
348 
349 	  case vpiSize:
350 	    return parent->get_word_size();
351 
352 	  case vpiLeftRange:
353             val.format = vpiIntVal;
354 	    parent->get_left_range()->vpi_get_value(&val);
355             assert(val.format == vpiIntVal);
356             return val.value.integer;
357 
358 	  case vpiRightRange:
359             val.format = vpiIntVal;
360 	    parent->get_right_range()->vpi_get_value(&val);
361             assert(val.format == vpiIntVal);
362             return val.value.integer;
363 
364 	  case vpiIndex:
365 	    {
366 		  int base_offset = 0;
367 		  struct __vpiArray*base = dynamic_cast<__vpiArray*> (parent);
368 		  if (base) {
369 			val.format = vpiIntVal;
370 			base->first_addr.vpi_get_value(&val);
371 			base_offset += val.value.integer;
372 		  }
373 		  val.format = vpiIntVal;
374 		  obj->as_index.vpi_get_value(&val);
375 		  assert(val.format == vpiIntVal);
376 		  return val.value.integer + base_offset;
377 	    }
378 
379 	  case vpiAutomatic:
380 	    return parent->get_scope()->is_automatic()? 1 : 0;
381 
382 #if defined(CHECK_WITH_VALGRIND) || defined(BR916_STOPGAP_FIX)
383 	  case _vpiFromThr:
384 	    return _vpiNoThr;
385 #endif
386 
387 	  default:
388 	    return 0;
389       }
390 }
391 
392 
vpi_get(int code)393 int __vpiArrayVthrA::vpi_get(int code)
394 {
395       switch (code) {
396 	  case vpiLineNo:
397 	    return 0; // Not implemented for now!
398 
399 	  case vpiSize:
400 	    return array->get_word_size();
401 
402 	  case vpiLeftRange:
403 	    return array->msb.get_value();
404 
405 	  case vpiRightRange:
406 	    return array->lsb.get_value();
407 
408 	  case vpiIndex:
409 	    return (int)get_address() + array->first_addr.get_value();
410 
411 	  case vpiAutomatic:
412 	    return array->get_scope()->is_automatic() ? 1 : 0;
413 
414 #if defined(CHECK_WITH_VALGRIND) || defined(BR916_STOPGAP_FIX)
415 	  case _vpiFromThr:
416 	    return _vpi_at_A;
417 #endif
418 
419 	  // If address_handle is not zero we definitely have a
420 	  // variable.
421 	  case vpiConstantSelect:
422 	    return address_handle == 0;
423 
424 	  default:
425 	    return 0;
426       }
427 }
428 
vpi_get_str(int code)429 char* __vpiArrayVthrA::vpi_get_str(int code)
430 {
431       if (code == vpiFile) {  // Not implemented for now!
432             return simple_set_rbuf_str(file_names[0]);
433       }
434 
435       char sidx [64];
436       snprintf(sidx, 63, "%d", (int)get_address() + array->first_addr.get_value());
437       return generic_get_str(code, array->get_scope(), array->name, sidx);
438 }
439 
vpi_get_value(p_vpi_value vp)440 void __vpiArrayVthrA::vpi_get_value(p_vpi_value vp)
441 {
442       assert(array);
443 
444       unsigned index = get_address();
445       if (vpi_array_is_real(array)) {
446 	    double tmp = array->get_word_r(index);
447 	    vpip_real_get_value(tmp, vp);
448       } else if (vpi_array_is_string(array)) {
449 	    string tmp = array->get_word_str(index);
450 	    vpip_string_get_value(tmp, vp);
451       } else {
452 	    vvp_vector4_t tmp = array->get_word(index);
453 	    unsigned width = array->get_word_size();
454 	    vpip_vec4_get_value(tmp, width, array->signed_flag, vp);
455       }
456 }
457 
vpi_put_value(p_vpi_value vp,int)458 vpiHandle __vpiArrayVthrA::vpi_put_value(p_vpi_value vp, int)
459 {
460       unsigned index = get_address();
461 
462       assert(array);
463       assert(index < array->get_size());
464 
465       if (vpi_array_is_real(array)) {
466 	    double val = real_from_vpi_value(vp);
467 	    array->set_word(index, val);
468       } else {
469 	    unsigned width = array->get_word_size();
470 	    vvp_vector4_t val = vec4_from_vpi_value(vp, width);
471 	    array->set_word(index, 0, val);
472       }
473 
474       return this;
475 }
476 
vpi_handle(int code)477 vpiHandle __vpiArrayVthrA::vpi_handle(int code)
478 {
479       switch (code) {
480 	  case vpiIndex:
481 	    break;  // Not implemented!
482 
483 	  case vpiLeftRange:
484 	    return &array->msb;
485 
486 	  case vpiRightRange:
487 	    return &array->lsb;
488 
489 	  case vpiParent:
490 	  case vpiArray:
491 	    return array;
492 
493 	  case vpiScope:
494 	    return array->get_scope();
495 
496 	  case vpiModule:
497 	    return vpip_module(array->get_scope());
498       }
499 
500       return 0;
501 }
502 
503 
vpi_get(int code)504 int __vpiArrayVthrAPV::vpi_get(int code)
505 {
506       switch (code) {
507 	  case vpiLineNo:
508 	    return 0; // Not implemented for now!
509 
510 	  case vpiSize:
511 	    return part_wid;
512 
513 	  case vpiLeftRange:
514 	    return part_bit + part_wid - 1;
515 
516 	  case vpiRightRange:
517 	    return part_bit;
518 
519 	  case vpiAutomatic:
520 	    return array->get_scope()->is_automatic() ? 1 : 0;
521 
522 #if defined(CHECK_WITH_VALGRIND) || defined(BR916_STOPGAP_FIX)
523 	  case _vpiFromThr:
524 	    return _vpi_at_APV;
525 #endif
526 
527 	  case vpiConstantSelect:
528 	    return 1;
529 
530 	  default:
531 	    return 0;
532       }
533 }
534 
vpi_get_str(int code)535 char* __vpiArrayVthrAPV::vpi_get_str(int code)
536 {
537       if (code == vpiFile) {  // Not implemented for now!
538             return simple_set_rbuf_str(file_names[0]);
539       }
540 
541       char sidx [64];
542       snprintf(sidx, 63, "%u", word_sel + array->first_addr.get_value());
543       return generic_get_str(code, array->get_scope(), array->name, sidx);
544 }
545 
vpi_get_value(p_vpi_value vp)546 void __vpiArrayVthrAPV::vpi_get_value(p_vpi_value vp)
547 {
548       assert(array);
549 
550       unsigned index = word_sel;
551       if (vpi_array_is_real(array)) {
552 	    double tmp = array->get_word_r(index);
553 	    vpip_real_get_value(tmp, vp);
554       } else {
555 	    vvp_vector4_t tmp = array->get_word(index);
556 	    tmp = tmp.subvalue(part_bit, part_wid);
557 	    vpip_vec4_get_value(tmp, part_wid, array->signed_flag, vp);
558       }
559 }
560 
vpi_handle(int code)561 vpiHandle __vpiArrayVthrAPV::vpi_handle(int code)
562 {
563       switch (code) {
564             // Not currently implemented. We would need to create a VPI
565             // object for the memory word.
566 	  case vpiParent:
567 	    return 0;
568 
569             // Not part of the Verilog standard. We use this internally.
570 	  case vpiArray:
571 	    return array;
572 
573 	  case vpiScope:
574 	    return array->get_scope();
575 
576 	  case vpiModule:
577 	    return vpip_module(array->get_scope());
578       }
579 
580       return 0;
581 }
582 
set_word(unsigned address,unsigned part_off,const vvp_vector4_t & val)583 void __vpiArray::set_word(unsigned address, unsigned part_off, const vvp_vector4_t&val)
584 {
585       if (address >= get_size())
586 	    return;
587 
588       if (vals4) {
589 	    assert(nets == 0);
590 	    if (part_off != 0 || val.size() != vals_width) {
591 		  vvp_vector4_t tmp = vals4->get_word(address);
592 		  if ((part_off + val.size()) > tmp.size()) {
593 			cerr << "part_off=" << part_off
594 			     << " val.size()=" << val.size()
595 			     << " vals[address].size()=" << tmp.size()
596 			     << " vals_width=" << vals_width << endl;
597 			assert(0);
598 		  }
599 		  tmp.set_vec(part_off, val);
600 		  vals4->set_word(address, tmp);
601 	    } else {
602 		  vals4->set_word(address, val);
603 	    }
604 	    word_change(address);
605 	    return;
606       }
607 
608       if (vals) {
609 	    assert(nets == 0);
610 	      // FIXME: For now, assume no part select of word?
611 	    assert(part_off==0);
612 	    assert(val.size() == vals_width);
613 	    vals->set_word(address, val);
614 	    word_change(address);
615 	    return;
616       }
617 
618       assert(nets != 0);
619 
620 	// Select the word of the array that we affect.
621       vpiHandle word = nets[address];
622       struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(word);
623       assert(vsig);
624 
625       vsig->node->send_vec4_pv(val, part_off, val.size(), vpip_size(vsig), 0);
626       word_change(address);
627 }
628 
set_word(unsigned address,double val)629 void __vpiArray::set_word(unsigned address, double val)
630 {
631       assert(vals != 0);
632       assert(nets == 0);
633 
634       if (address >= vals->get_size())
635 	    return;
636 
637       vals->set_word(address, val);
638       word_change(address);
639 }
640 
set_word(unsigned address,const string & val)641 void __vpiArray::set_word(unsigned address, const string&val)
642 {
643       assert(vals != 0);
644       assert(nets == 0);
645 
646       if (address >= vals->get_size())
647 	    return;
648 
649       vals->set_word(address, val);
650       word_change(address);
651 }
652 
set_word(unsigned address,const vvp_object_t & val)653 void __vpiArray::set_word(unsigned address, const vvp_object_t&val)
654 {
655       assert(vals != 0);
656       assert(nets == 0);
657 
658       if (address >= vals->get_size())
659 	    return;
660 
661       vals->set_word(address, val);
662       word_change(address);
663 }
664 
get_word(unsigned address)665 vvp_vector4_t __vpiArray::get_word(unsigned address)
666 {
667       if (vals4) {
668 	    assert(nets == 0);
669 	    assert(vals == 0);
670 	    return vals4->get_word(address);
671       }
672 
673       if (vals) {
674 	    assert(nets == 0);
675 	    assert(vals4== 0);
676 	    if (address >= vals->get_size())
677 		  return vvp_vector4_t(vals_width, BIT4_X);
678 
679 	    vvp_vector4_t val;
680 	    vals->get_word(address, val);
681 	    return val;
682       }
683 
684       assert(vals4 == 0);
685       assert(vals == 0);
686       assert(nets != 0);
687 
688       if (address >= get_size()) {
689 	      // Reading outside the array. Return X's but get the
690 	      // width by looking at a word that we know is present.
691 	    assert(get_size() > 0);
692 	    vpiHandle word = nets[0];
693 	    assert(word);
694 	    struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(word);
695 	    assert(vsig);
696 	    vvp_signal_value*sig = dynamic_cast<vvp_signal_value*> (vsig->node->fil);
697 	    assert(sig);
698 	    return vvp_vector4_t(sig->value_size(), BIT4_X);
699       }
700 
701       vpiHandle word = nets[address];
702       struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(word);
703       assert(vsig);
704       vvp_signal_value*sig = dynamic_cast<vvp_signal_value*> (vsig->node->fil);
705       assert(sig);
706 
707       vvp_vector4_t val;
708       sig->vec4_value(val);
709       return val;
710 }
711 
get_word_r(unsigned address)712 double __vpiArray::get_word_r(unsigned address)
713 {
714       if (vals) {
715 	    assert(vals4 == 0);
716 	    assert(nets  == 0);
717 	      // In this context, address out of bounds returns 0.0
718 	      // instead of an error.
719 	    if (address >= vals->get_size())
720 		  return 0.0;
721 
722 	    double val;
723 	    vals->get_word(address, val);
724 	    return val;
725       }
726 
727       assert(nets);
728       vpiHandle word = nets[address];
729       struct __vpiRealVar*vsig = dynamic_cast<__vpiRealVar*>(word);
730       assert(vsig);
731       vvp_signal_value*sig = dynamic_cast<vvp_signal_value*> (vsig->net->fil);
732       assert(sig);
733 
734       double val = sig->real_value();
735       return val;
736 }
737 
get_word_obj(unsigned address,vvp_object_t & val)738 void __vpiArray::get_word_obj(unsigned address, vvp_object_t&val)
739 {
740       if (vals) {
741 	    assert(vals4 == 0);
742 	    assert(nets  == 0);
743 	      // In this context, address out of bounds returns 0.0
744 	      // instead of an error.
745 	    if (address >= vals->get_size()) {
746 		  val = vvp_object_t();
747 		  return;
748 	    }
749 
750 	    vals->get_word(address, val);
751 	    return;
752       }
753 
754       assert(nets);
755 	// Arrays of string nets not implemented!
756       assert(0);
757       return;
758 }
759 
get_word_str(unsigned address)760 string __vpiArray::get_word_str(unsigned address)
761 {
762       if (vals) {
763 	    assert(vals4 == 0);
764 	    assert(nets  == 0);
765 	      // In this context, address out of bounds returns 0.0
766 	      // instead of an error.
767 	    if (address >= vals->get_size())
768 		  return "";
769 
770 	    string val;
771 	    vals->get_word(address, val);
772 	    return val;
773       }
774 
775       assert(nets);
776 	// Arrays of string nets not implemented!
777       assert(0);
778       return "";
779 }
780 
vpip_make_array(char * label,const char * name,int first_addr,int last_addr,bool signed_flag)781 vpiHandle vpip_make_array(char*label, const char*name,
782 				 int first_addr, int last_addr,
783 				 bool signed_flag)
784 {
785       struct __vpiArray*obj = new __vpiArray;
786 
787       obj->signed_flag = signed_flag;
788 
789 	// Assume increasing addresses.
790       if (last_addr >= first_addr) {
791 	    obj->swap_addr = false;
792       } else {
793 	    obj->swap_addr = true;
794 	    int tmp = last_addr;
795 	    last_addr = first_addr;
796 	    first_addr = tmp;
797       }
798       assert(last_addr >= first_addr);
799       unsigned array_count = last_addr+1-first_addr;
800 
801 	// For now, treat all arrays as memories. This is not quite
802 	// correct, as arrays are arrays with memories a special case.
803       obj->scope = vpip_peek_current_scope();
804       obj->name  = vpip_name_string(name);
805       obj->array_count = array_count;
806 
807       obj->first_addr.set_value(first_addr);
808       obj->last_addr .set_value(last_addr);
809 
810 	// Start off now knowing if we are nets or variables.
811       obj->nets = 0;
812       obj->vals4 = 0;
813       obj->vals  = 0;
814       obj->vals_width = 0;
815       obj->vals_words = 0;
816 
817 	// Initialize (clear) the read-ports list.
818       obj->ports_ = 0;
819       obj->vpi_callbacks = 0;
820 
821 	/* Add this symbol to the array_symbols table for later lookup. */
822       if (!array_table)
823 	    array_table = new symbol_map_s<struct __vpiArray>;
824 
825       assert(!array_find(label));
826       array_table->sym_set_value(label, obj);
827 
828 	/* Add this into the table of VPI objects. This is used for
829 	   contexts that try to look up VPI objects in
830 	   general. (i.e. arguments to vpi_task calls.) */
831       compile_vpi_symbol(label, obj);
832 
833 	/* Blindly attach to the scope as an object. */
834       vpip_attach_to_current_scope(obj);
835 
836       return obj;
837 }
838 
alias_word(unsigned long addr,vpiHandle word,int msb_,int lsb_)839 void __vpiArray::alias_word(unsigned long addr, vpiHandle word, int msb_, int lsb_)
840 {
841       assert(msb.get_value() == msb_);
842       assert(lsb.get_value() == lsb_);
843       assert(addr < get_size());
844       assert(nets);
845       nets[addr] = word;
846 }
847 
attach_word(unsigned addr,vpiHandle word)848 void __vpiArray::attach_word(unsigned addr, vpiHandle word)
849 {
850       assert(addr < get_size());
851       assert(nets);
852       nets[addr] = word;
853 
854       if (struct __vpiSignal*sig = dynamic_cast<__vpiSignal*>(word)) {
855 	    vvp_net_t*net = sig->node;
856 	    assert(net);
857 	    vvp_vpi_callback*fun = dynamic_cast<vvp_vpi_callback*>(net->fil);
858 	    assert(fun);
859 	    fun->attach_as_word(this, addr);
860 	    sig->is_netarray = 1;
861 	    sig->within.parent = this;
862 	    sig->id.index = new __vpiDecConst(addr + first_addr.get_value());
863 	      // Now we know the data type, update the array signed_flag.
864 	    signed_flag = sig->signed_flag;
865 	    return;
866       }
867 
868       if (struct __vpiRealVar*sig = dynamic_cast<__vpiRealVar*>(word)) {
869 	    vvp_net_t*net = sig->net;
870 	    assert(net);
871 	    vvp_vpi_callback*fun = dynamic_cast<vvp_vpi_callback*>(net->fil);
872 	    assert(fun);
873 	    fun->attach_as_word(this, addr);
874 	    sig->is_netarray = 1;
875 	    sig->within.parent = this;
876 	    sig->id.index = new __vpiDecConst(addr + first_addr.get_value());
877 	      // Now we know the data type, update the array signed_flag.
878 	    signed_flag = true;
879 	    return;
880       }
881 }
882 
compile_var_array(char * label,char * name,int last,int first,int msb,int lsb,char signed_flag)883 void compile_var_array(char*label, char*name, int last, int first,
884 		   int msb, int lsb, char signed_flag)
885 {
886       vpiHandle obj = vpip_make_array(label, name, first, last,
887                                       signed_flag != 0);
888 
889       struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj);
890 
891 	/* Make the words. */
892       arr->vals_width = labs(msb-lsb) + 1;
893       if (vpip_peek_current_scope()->is_automatic()) {
894             arr->vals4 = new vvp_vector4array_aa(arr->vals_width,
895 						 arr->get_size());
896       } else {
897             arr->vals4 = new vvp_vector4array_sa(arr->vals_width,
898 						 arr->get_size());
899       }
900       arr->msb.set_value(msb);
901       arr->lsb.set_value(lsb);
902 
903       count_var_arrays += 1;
904       count_var_array_words += arr->get_size();
905 
906       free(label);
907       delete[] name;
908 }
909 
compile_var2_array(char * label,char * name,int last,int first,int msb,int lsb,bool signed_flag)910 void compile_var2_array(char*label, char*name, int last, int first,
911 		   int msb, int lsb, bool signed_flag)
912 {
913       vpiHandle obj = vpip_make_array(label, name, first, last, signed_flag);
914 
915       struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj);
916 
917 	/* Make the words. */
918       arr->msb.set_value(msb);
919       arr->lsb.set_value(lsb);
920       arr->vals_width = labs(msb-lsb) + 1;
921 
922       assert(! arr->nets);
923       if (lsb == 0 && msb == 7 && signed_flag) {
924 	    arr->vals = new vvp_darray_atom<int8_t>(arr->get_size());
925       } else if (lsb == 0 && msb == 7 && !signed_flag) {
926 	    arr->vals = new vvp_darray_atom<uint8_t>(arr->get_size());
927       } else if (lsb == 0 && msb == 15 && signed_flag) {
928 	    arr->vals = new vvp_darray_atom<int16_t>(arr->get_size());
929       } else if (lsb == 0 && msb == 15 && !signed_flag) {
930 	    arr->vals = new vvp_darray_atom<uint16_t>(arr->get_size());
931       } else if (lsb == 0 && msb == 31 && signed_flag) {
932 	    arr->vals = new vvp_darray_atom<int32_t>(arr->get_size());
933       } else if (lsb == 0 && msb == 31 && !signed_flag) {
934 	    arr->vals = new vvp_darray_atom<uint32_t>(arr->get_size());
935       } else if (lsb == 0 && msb == 63 && signed_flag) {
936 	    arr->vals = new vvp_darray_atom<int64_t>(arr->get_size());
937       } else if (lsb == 0 && msb == 63 && !signed_flag) {
938 	    arr->vals = new vvp_darray_atom<uint64_t>(arr->get_size());
939       } else {
940 	    arr->vals = new vvp_darray_vec2(arr->get_size(), arr->vals_width);
941       }
942       count_var_arrays += 1;
943       count_var_array_words += arr->get_size();
944 
945       free(label);
946       delete[] name;
947 }
948 
compile_real_array(char * label,char * name,int last,int first)949 void compile_real_array(char*label, char*name, int last, int first)
950 {
951       vpiHandle obj = vpip_make_array(label, name, first, last, true);
952 
953       struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj);
954 
955 	/* Make the words. */
956       arr->vals = new vvp_darray_real(arr->get_size());
957       arr->vals_width = 1;
958 
959       count_real_arrays += 1;
960       count_real_array_words += arr->get_size();
961 
962       free(label);
963       delete[] name;
964 }
965 
compile_string_array(char * label,char * name,int last,int first)966 void compile_string_array(char*label, char*name, int last, int first)
967 {
968       vpiHandle obj = vpip_make_array(label, name, first, last, true);
969 
970       struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj);
971 
972 	/* Make the words. */
973       arr->vals = new vvp_darray_string(arr->get_size());
974       arr->vals_width = 1;
975 
976       count_real_arrays += 1;
977       count_real_array_words += arr->get_size();
978 
979       free(label);
980       delete[] name;
981 }
982 
compile_object_array(char * label,char * name,int last,int first)983 void compile_object_array(char*label, char*name, int last, int first)
984 {
985       vpiHandle obj = vpip_make_array(label, name, first, last, true);
986 
987       struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj);
988 
989 	/* Make the words. */
990       arr->vals = new vvp_darray_object(arr->get_size());
991       arr->vals_width = 1;
992 
993       count_real_arrays += 1;
994       count_real_array_words += arr->get_size();
995 
996       free(label);
997       delete[] name;
998 }
999 
compile_net_array(char * label,char * name,int last,int first)1000 void compile_net_array(char*label, char*name, int last, int first)
1001 {
1002 	// At this point we don't know the array data type, so we
1003 	// initialise signed_flag to false. This will be corrected
1004 	// (if necessary) when we attach words to the array.
1005       vpiHandle obj = vpip_make_array(label, name, first, last, false);
1006 
1007       struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj);
1008       arr->nets = (vpiHandle*)calloc(arr->get_size(), sizeof(vpiHandle));
1009 
1010       count_net_arrays += 1;
1011       count_net_array_words += arr->get_size();
1012 
1013       free(label);
1014       delete[] name;
1015 }
1016 
1017 class vvp_fun_arrayport  : public vvp_net_fun_t {
1018 
1019     public:
1020       explicit vvp_fun_arrayport(vvp_array_t mem, vvp_net_t*net);
1021       explicit vvp_fun_arrayport(vvp_array_t mem, vvp_net_t*net, long addr);
1022       ~vvp_fun_arrayport();
1023 
1024       virtual void check_word_change(unsigned long addr) = 0;
1025 
1026     protected:
1027       vvp_array_t arr_;
1028       vvp_net_t  *net_;
1029       unsigned long addr_;
1030 
1031       friend void array_attach_port(vvp_array_t, vvp_fun_arrayport*);
1032       friend void __vpiArray::word_change(unsigned long);
1033       vvp_fun_arrayport*next_;
1034 };
1035 
vvp_fun_arrayport(vvp_array_t mem,vvp_net_t * net)1036 vvp_fun_arrayport::vvp_fun_arrayport(vvp_array_t mem, vvp_net_t*net)
1037 : arr_(mem), net_(net), addr_(0)
1038 {
1039       next_ = 0;
1040 }
1041 
vvp_fun_arrayport(vvp_array_t mem,vvp_net_t * net,long addr)1042 vvp_fun_arrayport::vvp_fun_arrayport(vvp_array_t mem, vvp_net_t*net, long addr)
1043 : arr_(mem), net_(net), addr_(addr)
1044 {
1045       next_ = 0;
1046 }
1047 
~vvp_fun_arrayport()1048 vvp_fun_arrayport::~vvp_fun_arrayport()
1049 {
1050 }
1051 
1052 class vvp_fun_arrayport_sa  : public vvp_fun_arrayport {
1053 
1054     public:
1055       explicit vvp_fun_arrayport_sa(vvp_array_t mem, vvp_net_t*net);
1056       explicit vvp_fun_arrayport_sa(vvp_array_t mem, vvp_net_t*net, long addr);
1057       ~vvp_fun_arrayport_sa();
1058 
1059       void check_word_change(unsigned long addr);
1060 
1061       void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
1062                      vvp_context_t);
1063 
1064     private:
1065 };
1066 
vvp_fun_arrayport_sa(vvp_array_t mem,vvp_net_t * net)1067 vvp_fun_arrayport_sa::vvp_fun_arrayport_sa(vvp_array_t mem, vvp_net_t*net)
1068 : vvp_fun_arrayport(mem, net)
1069 {
1070 }
1071 
vvp_fun_arrayport_sa(vvp_array_t mem,vvp_net_t * net,long addr)1072 vvp_fun_arrayport_sa::vvp_fun_arrayport_sa(vvp_array_t mem, vvp_net_t*net, long addr)
1073 : vvp_fun_arrayport(mem, net, addr)
1074 {
1075 }
1076 
~vvp_fun_arrayport_sa()1077 vvp_fun_arrayport_sa::~vvp_fun_arrayport_sa()
1078 {
1079 }
1080 
recv_vec4(vvp_net_ptr_t port,const vvp_vector4_t & bit,vvp_context_t)1081 void vvp_fun_arrayport_sa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
1082                                      vvp_context_t)
1083 {
1084       bool addr_valid_flag;
1085 
1086       switch (port.port()) {
1087 
1088 	  case 0: // Address input
1089 	    addr_valid_flag = vector4_to_value(bit, addr_);
1090 	    if (! addr_valid_flag)
1091 		  addr_ = arr_->get_size();
1092 	    if (vpi_array_is_real(arr_))
1093 		  port.ptr()->send_real(arr_->get_word_r(addr_), 0);
1094 	    else
1095 		  port.ptr()->send_vec4(arr_->get_word(addr_), 0);
1096 
1097 	    break;
1098 
1099 	  default:
1100 	    fprintf(stdout, "XXXX write ports not implemented.\n");
1101 	    assert(0);
1102       }
1103 }
1104 
check_word_change(unsigned long addr)1105 void vvp_fun_arrayport_sa::check_word_change(unsigned long addr)
1106 {
1107       if (addr != addr_) return;
1108 
1109       if (vpi_array_is_real(arr_)) {
1110 	    net_->send_real(arr_->get_word_r(addr_), 0);
1111       } else {
1112 	    net_->send_vec4(arr_->get_word(addr_), 0);
1113       }
1114 }
1115 
1116 class vvp_fun_arrayport_aa  : public vvp_fun_arrayport, public automatic_hooks_s {
1117 
1118     public:
1119       explicit vvp_fun_arrayport_aa(vvp_array_t mem, vvp_net_t*net);
1120       explicit vvp_fun_arrayport_aa(vvp_array_t mem, vvp_net_t*net, long addr);
1121       ~vvp_fun_arrayport_aa();
1122 
1123       void alloc_instance(vvp_context_t context);
1124       void reset_instance(vvp_context_t context);
1125 #ifdef CHECK_WITH_VALGRIND
1126       void free_instance(vvp_context_t context);
1127 #endif
1128 
1129       void check_word_change(unsigned long addr);
1130 
1131       void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
1132                      vvp_context_t context);
1133 
1134     private:
1135       void check_word_change_(unsigned long addr, vvp_context_t context);
1136 
1137       __vpiScope*context_scope_;
1138       unsigned context_idx_;
1139 };
1140 
vvp_fun_arrayport_aa(vvp_array_t mem,vvp_net_t * net)1141 vvp_fun_arrayport_aa::vvp_fun_arrayport_aa(vvp_array_t mem, vvp_net_t*net)
1142 : vvp_fun_arrayport(mem, net)
1143 {
1144       context_scope_ = vpip_peek_context_scope();
1145       context_idx_ = vpip_add_item_to_context(this, context_scope_);
1146 }
1147 
vvp_fun_arrayport_aa(vvp_array_t mem,vvp_net_t * net,long addr)1148 vvp_fun_arrayport_aa::vvp_fun_arrayport_aa(vvp_array_t mem, vvp_net_t*net, long addr)
1149 : vvp_fun_arrayport(mem, net, addr)
1150 {
1151       context_scope_ = vpip_peek_context_scope();
1152       context_idx_ = vpip_add_item_to_context(this, context_scope_);
1153 }
1154 
~vvp_fun_arrayport_aa()1155 vvp_fun_arrayport_aa::~vvp_fun_arrayport_aa()
1156 {
1157 }
1158 
alloc_instance(vvp_context_t context)1159 void vvp_fun_arrayport_aa::alloc_instance(vvp_context_t context)
1160 {
1161       unsigned long*addr = new unsigned long;
1162       vvp_set_context_item(context, context_idx_, addr);
1163 
1164       *addr = addr_;
1165 }
1166 
reset_instance(vvp_context_t context)1167 void vvp_fun_arrayport_aa::reset_instance(vvp_context_t context)
1168 {
1169       unsigned long*addr = static_cast<unsigned long*>
1170             (vvp_get_context_item(context, context_idx_));
1171 
1172       *addr = addr_;
1173 }
1174 
1175 #ifdef CHECK_WITH_VALGRIND
free_instance(vvp_context_t context)1176 void vvp_fun_arrayport_aa::free_instance(vvp_context_t context)
1177 {
1178       unsigned long*addr = static_cast<unsigned long*>
1179             (vvp_get_context_item(context, context_idx_));
1180       delete addr;
1181 }
1182 #endif
1183 
recv_vec4(vvp_net_ptr_t port,const vvp_vector4_t & bit,vvp_context_t context)1184 void vvp_fun_arrayport_aa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
1185                                      vvp_context_t context)
1186 {
1187       if (context) {
1188             unsigned long*addr = static_cast<unsigned long*>
1189                   (vvp_get_context_item(context, context_idx_));
1190 
1191             bool addr_valid_flag;
1192 
1193             switch (port.port()) {
1194 
1195                 case 0: // Address input
1196                   addr_valid_flag = vector4_to_value(bit, *addr);
1197                   if (! addr_valid_flag) *addr = arr_->get_size();
1198                   if (vpi_array_is_real(arr_)) {
1199 			port.ptr()->send_real(arr_->get_word_r(*addr),
1200 					      context);
1201                   } else {
1202 			port.ptr()->send_vec4(arr_->get_word(*addr),
1203 					      context);
1204                   }
1205                   break;
1206 
1207                 default:
1208                   fprintf(stdout, "XXXX write ports not implemented.\n");
1209                   assert(0);
1210             }
1211       } else {
1212             context = context_scope_->live_contexts;
1213             while (context) {
1214                   recv_vec4(port, bit, context);
1215                   context = vvp_get_next_context(context);
1216             }
1217       }
1218 }
1219 
check_word_change_(unsigned long addr,vvp_context_t context)1220 void vvp_fun_arrayport_aa::check_word_change_(unsigned long addr,
1221                                               vvp_context_t context)
1222 {
1223       unsigned long*port_addr = static_cast<unsigned long*>
1224             (vvp_get_context_item(context, context_idx_));
1225 
1226       if (addr != *port_addr)
1227 	    return;
1228 
1229       if (vpi_array_is_real(arr_)) {
1230 	    net_->send_real(arr_->get_word_r(addr), context);
1231       } else {
1232 	    net_->send_vec4(arr_->get_word(addr), context);
1233       }
1234 }
1235 
check_word_change(unsigned long addr)1236 void vvp_fun_arrayport_aa::check_word_change(unsigned long addr)
1237 {
1238       if (arr_->get_scope()->is_automatic()) {
1239             assert(vthread_get_wt_context());
1240             check_word_change_(addr, vthread_get_wt_context());
1241       } else {
1242             vvp_context_t context = context_scope_->live_contexts;
1243             while (context) {
1244                   check_word_change_(addr, context);
1245                   context = vvp_get_next_context(context);
1246             }
1247       }
1248 }
1249 
array_attach_port(vvp_array_t array,vvp_fun_arrayport * fun)1250 static void array_attach_port(vvp_array_t array, vvp_fun_arrayport*fun)
1251 {
1252       assert(fun->next_ == 0);
1253       fun->next_ = array->ports_;
1254       array->ports_ = fun;
1255       if (!array->get_scope()->is_automatic()) {
1256               /* propagate initial values for variable arrays */
1257             if (array->vals4) {
1258                   vvp_vector4_t tmp(array->vals_width, BIT4_X);
1259                   schedule_init_propagate(fun->net_, tmp);
1260             }
1261             if (array->vals) {
1262                   schedule_init_propagate(fun->net_, 0.0);
1263             }
1264       }
1265 }
1266 
1267 class array_word_value_callback : public value_callback {
1268     public:
array_word_value_callback(p_cb_data data)1269       inline explicit array_word_value_callback(p_cb_data data)
1270       : value_callback(data)
1271       { }
1272 
1273     public:
1274       long word_addr;
1275 };
1276 
word_change(unsigned long addr)1277 void __vpiArray::word_change(unsigned long addr)
1278 {
1279       for (vvp_fun_arrayport*cur = ports_; cur; cur = cur->next_)
1280 	    cur->check_word_change(addr);
1281 
1282 	// Run callbacks attached to the array itself.
1283       struct __vpiCallback *next = vpi_callbacks;
1284       struct __vpiCallback *prev = 0;
1285 
1286       while (next) {
1287 	    array_word_value_callback*cur = dynamic_cast<array_word_value_callback*>(next);
1288 	    next = cur->next;
1289 
1290 	      // Skip callbacks that are not for me. -1 is for every element.
1291 	    if (cur->word_addr != (long)addr && cur->word_addr != -1) {
1292 		  prev = cur;
1293 		  continue;
1294 	    }
1295 
1296 	      // For whole array callbacks we need to set the index.
1297 	    if (cur->word_addr == -1) {
1298 		  cur->cb_data.index = (PLI_INT32) ((int)addr +
1299 						    first_addr.get_value());
1300 	    }
1301 
1302 	    if (cur->cb_data.cb_rtn != 0) {
1303 		  if (cur->test_value_callback_ready()) {
1304 			if (cur->cb_data.value) {
1305 			      if (vpi_array_is_real(this)) {
1306 				    double val = 0.0;
1307 				    if (addr < vals->get_size())
1308 					  vals->get_word(addr, val);
1309 				    vpip_real_get_value(val, cur->cb_data.value);
1310 			      } else {
1311 				    vpip_vec4_get_value(vals4->get_word(addr),
1312 							vals_width,
1313 							signed_flag,
1314 							cur->cb_data.value);
1315 			      }
1316 			}
1317 
1318 			callback_execute(cur);
1319 		  }
1320 
1321 		  prev = cur;
1322 
1323 	    } else if (prev == 0) {
1324 
1325 		  vpi_callbacks = next;
1326 		  cur->next = 0;
1327 		  delete cur;
1328 
1329 	    } else {
1330 		  assert(prev->next == cur);
1331 		  prev->next = next;
1332 		  cur->next = 0;
1333 		  delete cur;
1334 	    }
1335       }
1336 }
1337 
1338 class array_resolv_list_t : public resolv_list_s {
1339 
1340     public:
array_resolv_list_t(char * lab)1341       explicit array_resolv_list_t(char*lab) : resolv_list_s(lab) {
1342 	    array = 0;
1343       }
1344 
1345       vvp_array_t*array;
1346       bool resolve(bool mes);
1347 
1348     private:
1349 };
1350 
resolve(bool mes)1351 bool array_resolv_list_t::resolve(bool mes)
1352 {
1353       *array = array_find(label());
1354       if (*array == 0) {
1355 	    assert(!mes);
1356 	    return false;
1357       }
1358       return true;
1359 }
1360 
1361 class array_port_resolv_list_t : public resolv_list_s {
1362 
1363     public:
1364       explicit array_port_resolv_list_t(char* lab, bool use_addr__,
1365                                         long addr__);
1366 
1367       vvp_net_t*ptr;
1368       bool use_addr;
1369       long addr;
1370       bool resolve(bool mes);
1371 
1372     private:
1373 };
1374 
array_port_resolv_list_t(char * lab,bool use_addr__,long addr__)1375 array_port_resolv_list_t::array_port_resolv_list_t(char *lab, bool use_addr__,
1376                                                    long addr__)
1377 : resolv_list_s(lab), use_addr(use_addr__), addr(addr__)
1378 {
1379       ptr = new vvp_net_t;
1380 }
1381 
resolve(bool mes)1382 bool array_port_resolv_list_t::resolve(bool mes)
1383 {
1384       vvp_array_t mem = array_find(label());
1385       if (mem == 0) {
1386 	    assert(mem || !mes);
1387 	    return false;
1388       }
1389 
1390       vvp_fun_arrayport*fun;
1391       if (use_addr)
1392             if (vpip_peek_current_scope()->is_automatic())
1393                   fun = new vvp_fun_arrayport_aa(mem, ptr, addr);
1394             else
1395                   fun = new vvp_fun_arrayport_sa(mem, ptr, addr);
1396       else
1397             if (vpip_peek_current_scope()->is_automatic())
1398                   fun = new vvp_fun_arrayport_aa(mem, ptr);
1399             else
1400                   fun = new vvp_fun_arrayport_sa(mem, ptr);
1401       ptr->fun = fun;
1402 
1403       array_attach_port(mem, fun);
1404 
1405       return true;
1406 }
1407 
1408 class array_word_part_callback : public array_word_value_callback {
1409     public:
1410       explicit array_word_part_callback(p_cb_data data);
1411       ~array_word_part_callback();
1412 
1413       bool test_value_callback_ready(void);
1414 
1415     private:
1416       char*value_bits_;
1417 };
1418 
array_word_part_callback(p_cb_data data)1419 array_word_part_callback::array_word_part_callback(p_cb_data data)
1420 : array_word_value_callback(data)
1421 {
1422 	// Get the initial value of the part, to use as a reference.
1423       struct __vpiArrayVthrAPV*apvword = dynamic_cast<__vpiArrayVthrAPV*>(data->obj);
1424       s_vpi_value tmp_value;
1425       tmp_value.format = vpiBinStrVal;
1426       apvword->vpi_get_value(&tmp_value);
1427 
1428       value_bits_ = new char[apvword->part_wid+1];
1429 
1430       memcpy(value_bits_, tmp_value.value.str, apvword->part_wid);
1431       value_bits_[apvword->part_wid] = 0;
1432 }
1433 
~array_word_part_callback()1434 array_word_part_callback::~array_word_part_callback()
1435 {
1436       delete[]value_bits_;
1437 }
1438 
test_value_callback_ready(void)1439 bool array_word_part_callback::test_value_callback_ready(void)
1440 {
1441       struct __vpiArrayVthrAPV*apvword = dynamic_cast<__vpiArrayVthrAPV*>(cb_data.obj);
1442       assert(apvword);
1443 
1444 	// Get a reference value that can be used to compare with an
1445 	// updated value.
1446       s_vpi_value tmp_value;
1447       tmp_value.format = vpiBinStrVal;
1448       apvword->vpi_get_value(&tmp_value);
1449 
1450       if (memcmp(value_bits_, tmp_value.value.str, apvword->part_wid) == 0)
1451 	    return false;
1452 
1453       memcpy(value_bits_, tmp_value.value.str, apvword->part_wid);
1454       return true;
1455 
1456 }
1457 
vpip_array_word_change(p_cb_data data)1458 value_callback*vpip_array_word_change(p_cb_data data)
1459 {
1460       struct __vpiArray*parent = 0;
1461       array_word_value_callback*cbh = 0;
1462       if (struct __vpiArrayWord*word = array_var_word_from_handle(data->obj)) {
1463 	    parent = (__vpiArray*) word->get_parent();
1464 	    unsigned addr = word->get_index();
1465 	    cbh = new array_word_value_callback(data);
1466 	    cbh->word_addr = addr;
1467 
1468       } else if (struct __vpiArrayVthrA*tword = dynamic_cast<__vpiArrayVthrA*>(data->obj)) {
1469 	    parent = tword->array;
1470 	    cbh = new array_word_value_callback(data);
1471 	    cbh->word_addr = tword->address;
1472 
1473       } else if (struct __vpiArrayVthrAPV*apvword = dynamic_cast<__vpiArrayVthrAPV*>(data->obj)) {
1474 	    parent = apvword->array;
1475 	    cbh = new array_word_part_callback(data);
1476 	    cbh->word_addr = apvword->word_sel;
1477       }
1478 
1479       assert(cbh);
1480       assert(parent);
1481       cbh->next = parent->vpi_callbacks;
1482       parent->vpi_callbacks = cbh;
1483 
1484       return cbh;
1485 }
1486 
vpip_array_change(p_cb_data data)1487 value_callback* vpip_array_change(p_cb_data data)
1488 {
1489       array_word_value_callback*cbh = new array_word_value_callback(data);
1490       assert(data->obj);
1491 
1492       struct __vpiArray*arr = dynamic_cast<__vpiArray*>(data->obj);
1493       cbh->word_addr = -1; // This is a callback for every element.
1494       cbh->next = arr->vpi_callbacks;
1495       arr->vpi_callbacks = cbh;
1496       return cbh;
1497 }
1498 
compile_array_port(char * label,char * array,char * addr)1499 void compile_array_port(char*label, char*array, char*addr)
1500 {
1501       array_port_resolv_list_t*resolv_mem
1502 	    = new array_port_resolv_list_t(array, false, 0);
1503 
1504       define_functor_symbol(label, resolv_mem->ptr);
1505       free(label);
1506 	// Connect the port-0 input as the address.
1507       input_connect(resolv_mem->ptr, 0, addr);
1508 
1509       resolv_submit(resolv_mem);
1510 }
1511 
compile_array_port(char * label,char * array,long addr)1512 void compile_array_port(char*label, char*array, long addr)
1513 {
1514       array_port_resolv_list_t*resolv_mem
1515 	    = new array_port_resolv_list_t(array, true, addr);
1516 
1517       define_functor_symbol(label, resolv_mem->ptr);
1518       free(label);
1519 
1520       resolv_submit(resolv_mem);
1521 }
1522 
compile_array_alias(char * label,char * name,char * src)1523 void compile_array_alias(char*label, char*name, char*src)
1524 {
1525       vvp_array_t mem = array_find(src);
1526       assert(mem);
1527 
1528       struct __vpiArray*obj = new __vpiArray;
1529 
1530       obj->scope = vpip_peek_current_scope();
1531       obj->name  = vpip_name_string(name);
1532       obj->array_count = mem->array_count;
1533       obj->signed_flag = mem->signed_flag;
1534 
1535 	// Need to set an accurate range of addresses.
1536       obj->first_addr = mem->first_addr;
1537       obj->last_addr  = mem->last_addr;
1538       obj->swap_addr = mem->swap_addr;
1539 
1540       obj->msb = mem->msb;
1541       obj->lsb = mem->lsb;
1542 
1543 	// Share the words with the source array.
1544       obj->nets = mem->nets;
1545       obj->vals4 = mem->vals4;
1546       obj->vals  = mem->vals;
1547       obj->vals_width = mem->vals_width;
1548       obj->vals_words = mem->vals_words;
1549 
1550       obj->ports_ = 0;
1551       obj->vpi_callbacks = 0;
1552 
1553       assert(array_table);
1554       assert(!array_find(label));
1555       array_table->sym_set_value(label, obj);
1556 
1557       compile_vpi_symbol(label, obj);
1558       vpip_attach_to_current_scope(obj);
1559 
1560       free(label);
1561       free(name);
1562       free(src);
1563 }
1564 
1565 /*
1566  * &A<label,addr>
1567  * This represents a VPI handle for an addressed array. This comes
1568  * from expressions like "label[addr]" where "label" is the array and
1569  * "addr" is the canonical address of the desired word.
1570  */
vpip_make_vthr_A(char * label,unsigned addr)1571 vpiHandle vpip_make_vthr_A(char*label, unsigned addr)
1572 {
1573       struct __vpiArrayVthrA*obj = new __vpiArrayVthrA;
1574 
1575       array_resolv_list_t*resolv_mem
1576 	    = new array_resolv_list_t(label);
1577 
1578       resolv_mem->array = &obj->array;
1579       resolv_submit(resolv_mem);
1580 
1581       obj->address_handle = 0;
1582       obj->address = addr;
1583 
1584       return obj;
1585 }
1586 
1587 /*
1588  * &A<label,symbol>
1589  * This represents a VPI handle for an addressed word, where the
1590  * word address is calculated from the VPI object that symbol
1591  * represents. The expression that leads to this looks like label[symbol].
1592  */
vpip_make_vthr_A(char * label,char * symbol)1593 vpiHandle vpip_make_vthr_A(char*label, char*symbol)
1594 {
1595       struct __vpiArrayVthrA*obj = new __vpiArrayVthrA;
1596 
1597       array_resolv_list_t*resolv_mem
1598 	    = new array_resolv_list_t(label);
1599 
1600       resolv_mem->array = &obj->array;
1601       resolv_submit(resolv_mem);
1602 
1603       obj->address_handle = 0;
1604       compile_vpi_lookup(&obj->address_handle, symbol);
1605       obj->address = 0;
1606 
1607       return obj;
1608 }
1609 
vpip_make_vthr_A(char * label,vpiHandle handle)1610 vpiHandle vpip_make_vthr_A(char*label, vpiHandle handle)
1611 {
1612       struct __vpiArrayVthrA*obj = new __vpiArrayVthrA;
1613 
1614       array_resolv_list_t*resolv_mem
1615 	    = new array_resolv_list_t(label);
1616 
1617       resolv_mem->array = &obj->array;
1618       resolv_submit(resolv_mem);
1619 
1620       obj->address_handle = handle;
1621       obj->address = 0;
1622 
1623       return obj;
1624 }
1625 
vpip_make_vthr_APV(char * label,unsigned index,unsigned bit,unsigned wid)1626 vpiHandle vpip_make_vthr_APV(char*label, unsigned index, unsigned bit, unsigned wid)
1627 {
1628       struct __vpiArrayVthrAPV*obj = new __vpiArrayVthrAPV;
1629 
1630       array_resolv_list_t*resolv_mem
1631 	    = new array_resolv_list_t(label);
1632 
1633       resolv_mem->array = &obj->array;
1634       resolv_submit(resolv_mem);
1635 
1636       obj->word_sel = index;
1637       obj->part_bit = bit;
1638       obj->part_wid = wid;
1639 
1640       return obj;
1641 }
1642 
compile_array_cleanup(void)1643 void compile_array_cleanup(void)
1644 {
1645       delete array_table;
1646       array_table = 0;
1647 }
1648 
1649 #ifdef CHECK_WITH_VALGRIND
memory_delete(vpiHandle item)1650 void memory_delete(vpiHandle item)
1651 {
1652       struct __vpiArray*arr = (struct __vpiArray*) item;
1653       if (arr->vals_words) delete [] (arr->vals_words-1);
1654 
1655 //      if (arr->vals4) {}
1656 // Delete the individual words?
1657 // constant_delete(handle)?
1658       delete arr->vals4;
1659 
1660 //      if (arr->vals) {}
1661 // Delete the individual words?
1662 // constant_delete(handle)?
1663       delete arr->vals;
1664 
1665       if (arr->nets) {
1666 	    for (unsigned idx = 0; idx < arr->get_size(); idx += 1) {
1667 		  if (struct __vpiSignal*sig =
1668 		      dynamic_cast<__vpiSignal*>(arr->nets[idx])) {
1669 // Delete the individual words?
1670 			constant_delete(sig->id.index);
1671 		    /* These should only be the real words. */
1672 		  } else {
1673 			assert(arr->nets[idx]->get_type_code() ==
1674 			       vpiRealVar);
1675 			struct __vpiRealVar *sigr = (struct __vpiRealVar *)
1676 			                            arr->nets[idx];
1677 			constant_delete(sigr->id.index);
1678 // Why are only the real words still here?
1679 			delete arr->nets[idx];
1680 		  }
1681 	    }
1682 	    free(arr->nets);
1683       }
1684 
1685       while (arr->vpi_callbacks) {
1686 	    struct __vpiCallback*tmp = arr->vpi_callbacks->next;
1687 	    delete arr->vpi_callbacks;
1688 	    arr->vpi_callbacks = tmp;
1689       }
1690 
1691       delete arr;
1692 }
1693 
A_delete(vpiHandle item)1694 void A_delete(vpiHandle item)
1695 {
1696       struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*) item;
1697       if (obj->address_handle) {
1698 	    switch (obj->address_handle->get_type_code()) {
1699 		case vpiMemoryWord:
1700 		  if (vpi_get(_vpiFromThr, obj->address_handle) == _vpi_at_A) {
1701 			A_delete(obj->address_handle);
1702 		  }
1703 		  break;
1704 		case vpiPartSelect:
1705 		  assert(vpi_get(_vpiFromThr, obj->address_handle) ==
1706 		         _vpi_at_PV);
1707 		  PV_delete(obj->address_handle);
1708 		  break;
1709 	    }
1710       }
1711 
1712       delete obj;
1713 }
1714 
APV_delete(vpiHandle item)1715 void APV_delete(vpiHandle item)
1716 {
1717       struct __vpiArrayVthrAPV*obj = (struct __vpiArrayVthrAPV*) item;
1718       delete obj;
1719 }
1720 #endif
1721