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