1 /*
2  * Copyright (c) 2012-2019 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  "class_type.h"
21 # include  "compile.h"
22 # include  "vpi_priv.h"
23 # include  "config.h"
24 # include  <map>
25 #ifdef CHECK_WITH_VALGRIND
26 # include  "vvp_cleanup.h"
27 #endif
28 # include  <cassert>
29 
30 using namespace std;
31 
32 /*
33  * This class_property_t class is an abstract base class for
34  * representing a property of an instance. The definition keeps and
35  * array (of pointers) of these in order to define the the class.
36  */
37 class class_property_t {
38     public:
class_property_t()39       inline class_property_t() { }
40       virtual ~class_property_t() =0;
41 	// How much space does an instance of this property require?
42       virtual size_t instance_size() const =0;
43 
set_offset(size_t off)44       void set_offset(size_t off) { offset_ = off; }
45 
46     public:
47       virtual void construct(char*buf) const;
48       virtual void destruct(char*buf) const;
49 
50       virtual void set_vec4(char*buf, const vvp_vector4_t&val);
51       virtual void get_vec4(char*buf, vvp_vector4_t&val);
52 
53       virtual void set_real(char*buf, double val);
54       virtual double get_real(char*buf);
55 
56       virtual void set_string(char*buf, const std::string&val);
57       virtual string get_string(char*buf);
58 
59       virtual void set_object(char*buf, const vvp_object_t&val, uint64_t element);
60       virtual void get_object(char*buf, vvp_object_t&val, uint64_t element);
61 
62 	// Implement polymorphic shallow copy.
63       virtual void copy(char*buf, char*src) = 0;
64 
65     protected:
66       size_t offset_;
67 };
68 
~class_property_t()69 class_property_t::~class_property_t()
70 {
71 }
72 
construct(char *) const73 void class_property_t::construct(char*) const
74 {
75 }
76 
destruct(char *) const77 void class_property_t::destruct(char*) const
78 {
79 }
80 
set_vec4(char *,const vvp_vector4_t &)81 void class_property_t::set_vec4(char*, const vvp_vector4_t&)
82 {
83       assert(0);
84 }
85 
get_vec4(char *,vvp_vector4_t &)86 void class_property_t::get_vec4(char*, vvp_vector4_t&)
87 {
88       assert(0);
89 }
90 
set_real(char *,double)91 void class_property_t::set_real(char*, double)
92 {
93       assert(0);
94 }
95 
get_real(char *)96 double class_property_t::get_real(char*)
97 {
98       assert(0);
99       return 0.0;
100 }
101 
set_string(char *,const string &)102 void class_property_t::set_string(char*, const string&)
103 {
104       assert(0);
105 }
106 
get_string(char *)107 string class_property_t::get_string(char*)
108 {
109       assert(0);
110       return "";
111 }
112 
set_object(char *,const vvp_object_t &,uint64_t)113 void class_property_t::set_object(char*, const vvp_object_t&, uint64_t)
114 {
115       assert(0);
116 }
117 
get_object(char *,vvp_object_t &,uint64_t)118 void class_property_t::get_object(char*, vvp_object_t&, uint64_t)
119 {
120       assert(0);
121 }
122 
123 /*
124  */
125 template <class T> class property_atom : public class_property_t {
126     public:
property_atom(void)127       inline explicit property_atom(void) { }
~property_atom()128       ~property_atom() { }
129 
instance_size() const130       size_t instance_size() const { return sizeof(T); }
131 
132     public:
construct(char * buf) const133       void construct(char*buf) const
134       { T*tmp = reinterpret_cast<T*> (buf+offset_);
135 	*tmp = 0;
136       }
137 
138       void set_vec4(char*buf, const vvp_vector4_t&val);
139       void get_vec4(char*buf, vvp_vector4_t&val);
140 
141       void copy(char*dst, char*src);
142 };
143 
144 class property_bit : public class_property_t {
145     public:
property_bit(size_t wid)146       explicit inline property_bit(size_t wid): wid_(wid) { }
~property_bit()147       ~property_bit() { }
148 
instance_size() const149       size_t instance_size() const { return sizeof(vvp_vector2_t); }
150 
151     public:
construct(char * buf) const152       void construct(char*buf) const
153       { new (buf+offset_) vvp_vector2_t (0, wid_); }
154 
destruct(char * buf) const155       void destruct(char*buf) const
156       { vvp_vector2_t*tmp = reinterpret_cast<vvp_vector2_t*>(buf+offset_);
157 	tmp->~vvp_vector2_t();
158       }
159 
160       void set_vec4(char*buf, const vvp_vector4_t&val);
161       void get_vec4(char*buf, vvp_vector4_t&val);
162 
163       void copy(char*dst, char*src);
164 
165     private:
166       size_t wid_;
167 };
168 
169 class property_logic : public class_property_t {
170     public:
property_logic(size_t wid)171       explicit inline property_logic(size_t wid): wid_(wid) { }
~property_logic()172       ~property_logic() { }
173 
instance_size() const174       size_t instance_size() const { return sizeof(vvp_vector4_t); }
175 
176     public:
construct(char * buf) const177       void construct(char*buf) const
178       { new (buf+offset_) vvp_vector4_t (0, wid_); }
179 
destruct(char * buf) const180       void destruct(char*buf) const
181       { vvp_vector4_t*tmp = reinterpret_cast<vvp_vector4_t*>(buf+offset_);
182 	tmp->~vvp_vector4_t();
183       }
184 
185       void set_vec4(char*buf, const vvp_vector4_t&val);
186       void get_vec4(char*buf, vvp_vector4_t&val);
187 
188       void copy(char*dst, char*src);
189 
190     private:
191       size_t wid_;
192 };
193 
194 template <class T> class property_real : public class_property_t {
195     public:
property_real(void)196       inline explicit property_real(void) { }
~property_real()197       ~property_real() { }
198 
instance_size() const199       size_t instance_size() const { return sizeof(T); }
200 
201     public:
construct(char * buf) const202       void construct(char*buf) const
203       { T*tmp = reinterpret_cast<T*> (buf+offset_);
204 	*tmp = 0.0;
205       }
206 
207       void set_real(char*buf, double val);
208       double get_real(char*buf);
209 
210       void copy(char*dst, char*src);
211 };
212 
213 class property_string : public class_property_t {
214     public:
property_string(void)215       inline explicit property_string(void) { }
~property_string()216       ~property_string() { }
217 
instance_size() const218       size_t instance_size() const { return sizeof(std::string); }
219 
220     public:
construct(char * buf) const221       void construct(char*buf) const
222       { /* string*tmp = */ new (buf+offset_) string; }
223 
destruct(char * buf) const224       void destruct(char*buf) const
225       { string*tmp = reinterpret_cast<string*> (buf+offset_);
226 	tmp->~string();
227       }
228 
229       void set_string(char*buf, const string&);
230       string get_string(char*buf);
231 
232       void copy(char*dst, char*src);
233 };
234 
235 class property_object : public class_property_t {
236     public:
property_object(uint64_t as)237       inline explicit property_object(uint64_t as): array_size_(as==0? 1 : as) { }
~property_object()238       ~property_object() { }
239 
instance_size() const240       size_t instance_size() const { return array_size_ * sizeof(vvp_object_t); }
241 
242     public:
243       void construct(char*buf) const;
244 
245       void destruct(char*buf) const;
246 
247       void set_object(char*buf, const vvp_object_t&, uint64_t);
248       void get_object(char*buf, vvp_object_t&, uint64_t);
249 
250       void copy(char*dst, char*src);
251 
252     private:
253       size_t array_size_;
254 };
255 
set_vec4(char * buf,const vvp_vector4_t & val)256 template <class T> void property_atom<T>::set_vec4(char*buf, const vvp_vector4_t&val)
257 {
258       T*tmp = reinterpret_cast<T*> (buf+offset_);
259       bool flag = vector4_to_value(val, *tmp, true, false);
260       assert(flag);
261 }
262 
get_vec4(char * buf,vvp_vector4_t & val)263 template <class T> void property_atom<T>::get_vec4(char*buf, vvp_vector4_t&val)
264 {
265       T*src = reinterpret_cast<T*> (buf+offset_);
266       const size_t tmp_cnt = sizeof(T)<sizeof(unsigned long)
267 				       ? 1
268 				       : sizeof(T) / sizeof(unsigned long);
269       unsigned long tmp[tmp_cnt];
270       tmp[0] = src[0];
271 
272       for (size_t idx = 1 ; idx < tmp_cnt ; idx += 1)
273 	    tmp[idx] = src[0] >> idx * 8 * sizeof(tmp[0]);
274 
275       val.resize(8*sizeof(T));
276       val.setarray(0, val.size(), tmp);
277 }
278 
copy(char * dst,char * src)279 template <class T> void property_atom<T>::copy(char*dst, char*src)
280 {
281       T*dst_obj = reinterpret_cast<T*> (dst+offset_);
282       T*src_obj = reinterpret_cast<T*> (src+offset_);
283       *dst_obj = *src_obj;
284 }
285 
set_vec4(char * buf,const vvp_vector4_t & val)286 void property_bit::set_vec4(char*buf, const vvp_vector4_t&val)
287 {
288       vvp_vector2_t*obj = reinterpret_cast<vvp_vector2_t*> (buf+offset_);
289       *obj = val;
290 }
291 
get_vec4(char * buf,vvp_vector4_t & val)292 void property_bit::get_vec4(char*buf, vvp_vector4_t&val)
293 {
294       vvp_vector2_t*obj = reinterpret_cast<vvp_vector2_t*> (buf+offset_);
295       val = vector2_to_vector4(*obj, obj->size());
296 }
297 
copy(char * dst,char * src)298 void property_bit::copy(char*dst, char*src)
299 {
300       vvp_vector2_t*dst_obj = reinterpret_cast<vvp_vector2_t*> (dst+offset_);
301       vvp_vector2_t*src_obj = reinterpret_cast<vvp_vector2_t*> (src+offset_);
302       *dst_obj = *src_obj;
303 }
304 
set_vec4(char * buf,const vvp_vector4_t & val)305 void property_logic::set_vec4(char*buf, const vvp_vector4_t&val)
306 {
307       vvp_vector4_t*obj = reinterpret_cast<vvp_vector4_t*> (buf+offset_);
308       *obj = val;
309 }
310 
get_vec4(char * buf,vvp_vector4_t & val)311 void property_logic::get_vec4(char*buf, vvp_vector4_t&val)
312 {
313       vvp_vector4_t*obj = reinterpret_cast<vvp_vector4_t*> (buf+offset_);
314       val = *obj;
315 }
316 
copy(char * dst,char * src)317 void property_logic::copy(char*dst, char*src)
318 {
319       vvp_vector4_t*dst_obj = reinterpret_cast<vvp_vector4_t*> (dst+offset_);
320       vvp_vector4_t*src_obj = reinterpret_cast<vvp_vector4_t*> (src+offset_);
321       *dst_obj = *src_obj;
322 }
323 
set_real(char * buf,double val)324 template <class T> void property_real<T>::set_real(char*buf, double val)
325 {
326       T*tmp = reinterpret_cast<T*>(buf+offset_);
327       *tmp = val;
328 }
329 
get_real(char * buf)330 template <class T> double property_real<T>::get_real(char*buf)
331 {
332       T*tmp = reinterpret_cast<T*>(buf+offset_);
333       return *tmp;
334 }
335 
copy(char * dst,char * src)336 template <class T> void property_real<T>::copy(char*dst, char*src)
337 {
338       T*dst_obj = reinterpret_cast<T*> (dst+offset_);
339       T*src_obj = reinterpret_cast<T*> (src+offset_);
340       *dst_obj = *src_obj;
341 }
342 
set_string(char * buf,const string & val)343 void property_string::set_string(char*buf, const string&val)
344 {
345       string*tmp = reinterpret_cast<string*>(buf+offset_);
346       *tmp = val;
347 }
348 
get_string(char * buf)349 string property_string::get_string(char*buf)
350 {
351       string*tmp = reinterpret_cast<string*>(buf+offset_);
352       return *tmp;
353 }
354 
copy(char * dst,char * src)355 void property_string::copy(char*dst, char*src)
356 {
357       string*dst_obj = reinterpret_cast<string*> (dst+offset_);
358       string*src_obj = reinterpret_cast<string*> (src+offset_);
359       *dst_obj = *src_obj;
360 }
361 
construct(char * buf) const362 void property_object::construct(char*buf) const
363 {
364       for (size_t idx = 0 ; idx < array_size_ ; idx += 1)
365 	    new (buf+offset_ + idx*sizeof(vvp_object_t)) vvp_object_t;
366 }
367 
destruct(char * buf) const368 void property_object::destruct(char*buf) const
369 {
370       vvp_object_t*tmp = reinterpret_cast<vvp_object_t*> (buf+offset_);
371       for (size_t idx = 0 ; idx < array_size_ ; idx += 1)
372 	    (tmp+idx)->~vvp_object_t();
373 }
374 
set_object(char * buf,const vvp_object_t & val,uint64_t idx)375 void property_object::set_object(char*buf, const vvp_object_t&val, uint64_t idx)
376 {
377       assert(idx < array_size_);
378       vvp_object_t*tmp = reinterpret_cast<vvp_object_t*>(buf+offset_);
379       tmp[idx] = val;
380 }
381 
get_object(char * buf,vvp_object_t & val,uint64_t idx)382 void property_object::get_object(char*buf, vvp_object_t&val, uint64_t idx)
383 {
384       assert(idx < array_size_);
385       vvp_object_t*tmp = reinterpret_cast<vvp_object_t*>(buf+offset_);
386       val = tmp[idx];
387 }
388 
copy(char * dst,char * src)389 void property_object::copy(char*dst, char*src)
390 {
391       vvp_object_t*dst_obj = reinterpret_cast<vvp_object_t*>(dst+offset_);
392       vvp_object_t*src_obj = reinterpret_cast<vvp_object_t*>(src+offset_);
393       for (size_t idx = 0 ; idx < array_size_ ; idx += 1)
394 	    dst_obj[idx] = src_obj[idx];
395 }
396 
397 /* **** */
398 
class_type(const string & nam,size_t nprop)399 class_type::class_type(const string&nam, size_t nprop)
400 : class_name_(nam), properties_(nprop)
401 {
402       instance_size_ = 0;
403 }
404 
~class_type()405 class_type::~class_type()
406 {
407       for (size_t idx = 0 ; idx < properties_.size() ; idx += 1)
408 	    delete properties_[idx].type;
409 }
410 
set_property(size_t idx,const string & name,const string & type,uint64_t array_size)411 void class_type::set_property(size_t idx, const string&name, const string&type, uint64_t array_size)
412 {
413       assert(idx < properties_.size());
414       properties_[idx].name = name;
415 
416       if (type == "b8")
417 	    properties_[idx].type = new property_atom<uint8_t>;
418       else if (type == "b16")
419 	    properties_[idx].type = new property_atom<uint16_t>;
420       else if (type == "b32")
421 	    properties_[idx].type = new property_atom<uint32_t>;
422       else if (type == "b64")
423 	    properties_[idx].type = new property_atom<uint64_t>;
424       else if (type == "sb8")
425 	    properties_[idx].type = new property_atom<int8_t>;
426       else if (type == "sb16")
427 	    properties_[idx].type = new property_atom<int16_t>;
428       else if (type == "sb32")
429 	    properties_[idx].type = new property_atom<int32_t>;
430       else if (type == "sb64")
431 	    properties_[idx].type = new property_atom<int64_t>;
432       else if (type == "r")
433 	    properties_[idx].type = new property_real<double>;
434       else if (type == "S")
435 	    properties_[idx].type = new property_string;
436       else if (type == "o")
437 	    properties_[idx].type = new property_object(array_size);
438       else if (type[0] == 'b') {
439 	    size_t wid = strtoul(type.c_str()+1, 0, 0);
440 	    properties_[idx].type = new property_bit(wid);
441       } else if (type[0] == 'L') {
442 	    size_t wid = strtoul(type.c_str()+1,0,0);
443 	    properties_[idx].type = new property_logic(wid);
444       } else if (type[0] == 's' && type[1] == 'L') {
445 	    size_t wid = strtoul(type.c_str()+2,0,0);
446 	    properties_[idx].type = new property_logic(wid);
447       } else {
448 	    properties_[idx].type = 0;
449       }
450 }
451 
finish_setup(void)452 void class_type::finish_setup(void)
453 {
454       map<size_t, vector<size_t> > size_map;
455 	// Add up all the sizes to get a total instance size. This
456 	// figures out how much memory a complete instance will need.
457       size_t accum = 0;
458       for (size_t idx = 0 ; idx < properties_.size() ; idx += 1) {
459 	    assert(properties_[idx].type);
460 	    size_t instance_size = properties_[idx].type->instance_size();
461 	    accum += instance_size;
462 	    size_map[instance_size].push_back(idx);
463       }
464 
465       instance_size_ = accum;
466 
467 	// Now allocate the properties to offsets within an instance
468 	// space. Allocate the properties largest objects first so
469 	// that they are assured better alignment.
470       accum = 0;
471       for (map<size_t, vector<size_t> >::reverse_iterator cur = size_map.rbegin()
472 		 ; cur != size_map.rend() ; ++ cur) {
473 	    for (size_t idx = 0 ; idx < cur->second.size() ; idx += 1) {
474 		  size_t pid = cur->second[idx];
475 		  class_property_t*ptype = properties_[pid].type;
476 		  assert(ptype->instance_size() == cur->first);
477 		  ptype->set_offset(accum);
478 		  accum += cur->first;
479 	    }
480       }
481 }
482 
instance_new() const483 class_type::inst_t class_type::instance_new() const
484 {
485       char*buf = new char [instance_size_];
486 
487       for (size_t idx = 0 ; idx < properties_.size() ; idx += 1)
488 	    properties_[idx].type->construct(buf);
489 
490       return reinterpret_cast<inst_t> (buf);
491 }
492 
instance_delete(class_type::inst_t obj) const493 void class_type::instance_delete(class_type::inst_t obj) const
494 {
495       char*buf = reinterpret_cast<char*> (obj);
496 
497       for (size_t idx = 0 ; idx < properties_.size() ; idx += 1)
498 	    properties_[idx].type->destruct(buf);
499 
500       delete[]buf;
501 }
502 
set_vec4(class_type::inst_t obj,size_t pid,const vvp_vector4_t & val) const503 void class_type::set_vec4(class_type::inst_t obj, size_t pid,
504 			  const vvp_vector4_t&val) const
505 {
506       char*buf = reinterpret_cast<char*> (obj);
507       assert(pid < properties_.size());
508       properties_[pid].type->set_vec4(buf, val);
509 }
510 
get_vec4(class_type::inst_t obj,size_t pid,vvp_vector4_t & val) const511 void class_type::get_vec4(class_type::inst_t obj, size_t pid,
512 			  vvp_vector4_t&val) const
513 {
514       char*buf = reinterpret_cast<char*> (obj);
515       assert(pid < properties_.size());
516       properties_[pid].type->get_vec4(buf, val);
517 }
518 
set_real(class_type::inst_t obj,size_t pid,double val) const519 void class_type::set_real(class_type::inst_t obj, size_t pid,
520 			  double val) const
521 {
522       char*buf = reinterpret_cast<char*> (obj);
523       assert(pid < properties_.size());
524       properties_[pid].type->set_real(buf, val);
525 }
526 
get_real(class_type::inst_t obj,size_t pid) const527 double class_type::get_real(class_type::inst_t obj, size_t pid) const
528 {
529       char*buf = reinterpret_cast<char*> (obj);
530       assert(pid < properties_.size());
531       return properties_[pid].type->get_real(buf);
532 }
533 
set_string(class_type::inst_t obj,size_t pid,const string & val) const534 void class_type::set_string(class_type::inst_t obj, size_t pid,
535 			    const string&val) const
536 {
537       char*buf = reinterpret_cast<char*> (obj);
538       assert(pid < properties_.size());
539       properties_[pid].type->set_string(buf, val);
540 }
541 
get_string(class_type::inst_t obj,size_t pid) const542 string class_type::get_string(class_type::inst_t obj, size_t pid) const
543 {
544       char*buf = reinterpret_cast<char*> (obj);
545       assert(pid < properties_.size());
546       return properties_[pid].type->get_string(buf);
547 }
548 
set_object(class_type::inst_t obj,size_t pid,const vvp_object_t & val,size_t idx) const549 void class_type::set_object(class_type::inst_t obj, size_t pid,
550 			    const vvp_object_t&val, size_t idx) const
551 {
552       char*buf = reinterpret_cast<char*> (obj);
553       assert(pid < properties_.size());
554       properties_[pid].type->set_object(buf, val, idx);
555 }
556 
get_object(class_type::inst_t obj,size_t pid,vvp_object_t & val,size_t idx) const557 void class_type::get_object(class_type::inst_t obj, size_t pid,
558 			    vvp_object_t&val, size_t idx) const
559 {
560       char*buf = reinterpret_cast<char*> (obj);
561       assert(pid < properties_.size());
562       properties_[pid].type->get_object(buf, val, idx);
563 }
564 
copy_property(class_type::inst_t dst,size_t pid,class_type::inst_t src) const565 void class_type::copy_property(class_type::inst_t dst, size_t pid, class_type::inst_t src) const
566 {
567       char*dst_buf = reinterpret_cast<char*> (dst);
568       char*src_buf = reinterpret_cast<char*> (src);
569 
570       assert(pid < properties_.size());
571 
572       properties_[pid].type->copy(dst_buf, src_buf);
573 }
574 
get_type_code(void) const575 int class_type::get_type_code(void) const
576 {
577       return vpiClassDefn;
578 }
579 
580 static class_type*compile_class = 0;
581 
compile_class_start(char * lab,char * nam,unsigned ntype)582 void compile_class_start(char*lab, char*nam, unsigned ntype)
583 {
584       assert(compile_class == 0);
585       compile_class = new class_type(nam, ntype);
586       compile_vpi_symbol(lab, compile_class);
587       free(lab);
588       delete[]nam;
589 }
590 
compile_class_property(unsigned idx,char * nam,char * typ,uint64_t array_size)591 void compile_class_property(unsigned idx, char*nam, char*typ, uint64_t array_size)
592 {
593       assert(compile_class);
594       compile_class->set_property(idx, nam, typ, array_size);
595       delete[]nam;
596       delete[]typ;
597 }
598 
compile_class_done(void)599 void compile_class_done(void)
600 {
601       __vpiScope*scope = vpip_peek_current_scope();
602       assert(scope);
603       assert(compile_class);
604       compile_class->finish_setup();
605       scope->classes[compile_class->class_name()] = compile_class;
606       compile_class = 0;
607 }
608 
609 #ifdef CHECK_WITH_VALGRIND
class_def_delete(class_type * item)610 void class_def_delete(class_type *item)
611 {
612       delete item;
613 }
614 #endif
615