/* * Copyright (c) 2012-2025 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "class_type.h" # include "compile.h" # include "vpi_priv.h" # include "config.h" # include #ifdef CHECK_WITH_VALGRIND # include "vvp_cleanup.h" #endif # include using namespace std; /* * This class_property_t class is an abstract base class for * representing a property of an instance. The definition keeps and * array (of pointers) of these in order to define the the class. */ class class_property_t { public: inline class_property_t() { } virtual ~class_property_t() =0; // How much space does an instance of this property require? virtual size_t instance_size() const =0; void set_offset(size_t off) { offset_ = off; } public: virtual void construct(char*buf) const; virtual void destruct(char*buf) const; virtual void set_vec4(char*buf, const vvp_vector4_t&val); virtual void get_vec4(char*buf, vvp_vector4_t&val); virtual void set_real(char*buf, double val); virtual double get_real(char*buf); virtual void set_string(char*buf, const std::string&val); virtual string get_string(char*buf); virtual void set_object(char*buf, const vvp_object_t&val, uint64_t element); virtual void get_object(char*buf, vvp_object_t&val, uint64_t element); // Implement polymorphic shallow copy. virtual void copy(char*buf, char*src) = 0; protected: size_t offset_; }; class_property_t::~class_property_t() { } void class_property_t::construct(char*) const { } void class_property_t::destruct(char*) const { } void class_property_t::set_vec4(char*, const vvp_vector4_t&) { assert(0); } void class_property_t::get_vec4(char*, vvp_vector4_t&) { assert(0); } void class_property_t::set_real(char*, double) { assert(0); } double class_property_t::get_real(char*) { assert(0); return 0.0; } void class_property_t::set_string(char*, const string&) { assert(0); } string class_property_t::get_string(char*) { assert(0); return ""; } void class_property_t::set_object(char*, const vvp_object_t&, uint64_t) { assert(0); } void class_property_t::get_object(char*, vvp_object_t&, uint64_t) { assert(0); } /* */ template class property_atom : public class_property_t { public: inline explicit property_atom(void) { } ~property_atom() { } size_t instance_size() const override { return sizeof(T); } public: void construct(char*buf) const override { T*tmp = reinterpret_cast (buf+offset_); *tmp = 0; } void set_vec4(char*buf, const vvp_vector4_t&val) override; void get_vec4(char*buf, vvp_vector4_t&val) override; void copy(char*dst, char*src) override; }; class property_bit : public class_property_t { public: explicit inline property_bit(size_t wid): wid_(wid) { } ~property_bit() { } size_t instance_size() const override { return sizeof(vvp_vector2_t); } public: void construct(char*buf) const override { new (buf+offset_) vvp_vector2_t (0, wid_); } void destruct(char*buf) const override { vvp_vector2_t*tmp = reinterpret_cast(buf+offset_); tmp->~vvp_vector2_t(); } void set_vec4(char*buf, const vvp_vector4_t&val) override; void get_vec4(char*buf, vvp_vector4_t&val) override; void copy(char*dst, char*src) override; private: size_t wid_; }; class property_logic : public class_property_t { public: explicit inline property_logic(size_t wid): wid_(wid) { } ~property_logic() { } size_t instance_size() const override { return sizeof(vvp_vector4_t); } public: void construct(char*buf) const override { new (buf+offset_) vvp_vector4_t (wid_); } void destruct(char*buf) const override { vvp_vector4_t*tmp = reinterpret_cast(buf+offset_); tmp->~vvp_vector4_t(); } void set_vec4(char*buf, const vvp_vector4_t&val) override; void get_vec4(char*buf, vvp_vector4_t&val) override; void copy(char*dst, char*src) override; private: size_t wid_; }; template class property_real : public class_property_t { public: inline explicit property_real(void) { } ~property_real() { } size_t instance_size() const override { return sizeof(T); } public: void construct(char*buf) const override { T*tmp = reinterpret_cast (buf+offset_); *tmp = 0.0; } void set_real(char*buf, double val) override; double get_real(char*buf) override; void copy(char*dst, char*src) override; }; class property_string : public class_property_t { public: inline explicit property_string(void) { } ~property_string() { } size_t instance_size() const override { return sizeof(std::string); } public: void construct(char*buf) const override { /* string*tmp = */ new (buf+offset_) string; } void destruct(char*buf) const override { string*tmp = reinterpret_cast (buf+offset_); tmp->~string(); } void set_string(char*buf, const string&) override; string get_string(char*buf) override; void copy(char*dst, char*src) override; }; class property_object : public class_property_t { public: inline explicit property_object(uint64_t as): array_size_(as==0? 1 : as) { } ~property_object() { } size_t instance_size() const override { return array_size_ * sizeof(vvp_object_t); } public: void construct(char*buf) const override; void destruct(char*buf) const override; void set_object(char*buf, const vvp_object_t&, uint64_t) override; void get_object(char*buf, vvp_object_t&, uint64_t) override; void copy(char*dst, char*src) override; private: size_t array_size_; }; template void property_atom::set_vec4(char*buf, const vvp_vector4_t&val) { T*tmp = reinterpret_cast (buf+offset_); bool flag = vector4_to_value(val, *tmp, true, false); assert(flag); } template void property_atom::get_vec4(char*buf, vvp_vector4_t&val) { T*src = reinterpret_cast (buf+offset_); const size_t tmp_cnt = sizeof(T)> idx * 8 * sizeof(tmp[0]); val.resize(8*sizeof(T)); val.setarray(0, val.size(), tmp); } template void property_atom::copy(char*dst, char*src) { T*dst_obj = reinterpret_cast (dst+offset_); T*src_obj = reinterpret_cast (src+offset_); *dst_obj = *src_obj; } void property_bit::set_vec4(char*buf, const vvp_vector4_t&val) { vvp_vector2_t*obj = reinterpret_cast (buf+offset_); *obj = val; } void property_bit::get_vec4(char*buf, vvp_vector4_t&val) { vvp_vector2_t*obj = reinterpret_cast (buf+offset_); val = vector2_to_vector4(*obj, obj->size()); } void property_bit::copy(char*dst, char*src) { vvp_vector2_t*dst_obj = reinterpret_cast (dst+offset_); vvp_vector2_t*src_obj = reinterpret_cast (src+offset_); *dst_obj = *src_obj; } void property_logic::set_vec4(char*buf, const vvp_vector4_t&val) { vvp_vector4_t*obj = reinterpret_cast (buf+offset_); *obj = val; } void property_logic::get_vec4(char*buf, vvp_vector4_t&val) { vvp_vector4_t*obj = reinterpret_cast (buf+offset_); val = *obj; } void property_logic::copy(char*dst, char*src) { vvp_vector4_t*dst_obj = reinterpret_cast (dst+offset_); vvp_vector4_t*src_obj = reinterpret_cast (src+offset_); *dst_obj = *src_obj; } template void property_real::set_real(char*buf, double val) { T*tmp = reinterpret_cast(buf+offset_); *tmp = val; } template double property_real::get_real(char*buf) { T*tmp = reinterpret_cast(buf+offset_); return *tmp; } template void property_real::copy(char*dst, char*src) { T*dst_obj = reinterpret_cast (dst+offset_); T*src_obj = reinterpret_cast (src+offset_); *dst_obj = *src_obj; } void property_string::set_string(char*buf, const string&val) { string*tmp = reinterpret_cast(buf+offset_); *tmp = val; } string property_string::get_string(char*buf) { string*tmp = reinterpret_cast(buf+offset_); return *tmp; } void property_string::copy(char*dst, char*src) { string*dst_obj = reinterpret_cast (dst+offset_); string*src_obj = reinterpret_cast (src+offset_); *dst_obj = *src_obj; } void property_object::construct(char*buf) const { for (size_t idx = 0 ; idx < array_size_ ; idx += 1) new (buf+offset_ + idx*sizeof(vvp_object_t)) vvp_object_t; } void property_object::destruct(char*buf) const { vvp_object_t*tmp = reinterpret_cast (buf+offset_); for (size_t idx = 0 ; idx < array_size_ ; idx += 1) (tmp+idx)->~vvp_object_t(); } void property_object::set_object(char*buf, const vvp_object_t&val, uint64_t idx) { assert(idx < array_size_); vvp_object_t*tmp = reinterpret_cast(buf+offset_); tmp[idx] = val; } void property_object::get_object(char*buf, vvp_object_t&val, uint64_t idx) { assert(idx < array_size_); vvp_object_t*tmp = reinterpret_cast(buf+offset_); val = tmp[idx]; } void property_object::copy(char*dst, char*src) { vvp_object_t*dst_obj = reinterpret_cast(dst+offset_); vvp_object_t*src_obj = reinterpret_cast(src+offset_); for (size_t idx = 0 ; idx < array_size_ ; idx += 1) dst_obj[idx] = src_obj[idx]; } /* **** */ class_type::class_type(const string&nam, size_t nprop) : class_name_(nam), properties_(nprop) { instance_size_ = 0; } class_type::~class_type() { for (size_t idx = 0 ; idx < properties_.size() ; idx += 1) delete properties_[idx].type; } void class_type::set_property(size_t idx, const string&name, const string&type, uint64_t array_size) { assert(idx < properties_.size()); properties_[idx].name = name; if (type == "b8") properties_[idx].type = new property_atom; else if (type == "b16") properties_[idx].type = new property_atom; else if (type == "b32") properties_[idx].type = new property_atom; else if (type == "b64") properties_[idx].type = new property_atom; else if (type == "sb8") properties_[idx].type = new property_atom; else if (type == "sb16") properties_[idx].type = new property_atom; else if (type == "sb32") properties_[idx].type = new property_atom; else if (type == "sb64") properties_[idx].type = new property_atom; else if (type == "r") properties_[idx].type = new property_real; else if (type == "S") properties_[idx].type = new property_string; else if (type == "o") properties_[idx].type = new property_object(array_size); else if (type[0] == 'b') { size_t wid = strtoul(type.c_str()+1, 0, 0); properties_[idx].type = new property_bit(wid); } else if (type[0] == 'L') { size_t wid = strtoul(type.c_str()+1,0,0); properties_[idx].type = new property_logic(wid); } else if (type[0] == 's' && type[1] == 'L') { size_t wid = strtoul(type.c_str()+2,0,0); properties_[idx].type = new property_logic(wid); } else { properties_[idx].type = 0; } } void class_type::finish_setup(void) { map > size_map; // Add up all the sizes to get a total instance size. This // figures out how much memory a complete instance will need. size_t accum = 0; for (size_t idx = 0 ; idx < properties_.size() ; idx += 1) { assert(properties_[idx].type); size_t instance_size = properties_[idx].type->instance_size(); accum += instance_size; size_map[instance_size].push_back(idx); } instance_size_ = accum; // Now allocate the properties to offsets within an instance // space. Allocate the properties largest objects first so // that they are assured better alignment. accum = 0; for (map >::reverse_iterator cur = size_map.rbegin() ; cur != size_map.rend() ; ++ cur) { for (size_t idx = 0 ; idx < cur->second.size() ; idx += 1) { size_t pid = cur->second[idx]; class_property_t*ptype = properties_[pid].type; assert(ptype->instance_size() == cur->first); ptype->set_offset(accum); accum += cur->first; } } } class_type::inst_t class_type::instance_new() const { char*buf = new char [instance_size_]; for (size_t idx = 0 ; idx < properties_.size() ; idx += 1) properties_[idx].type->construct(buf); return reinterpret_cast (buf); } void class_type::instance_delete(class_type::inst_t obj) const { char*buf = reinterpret_cast (obj); for (size_t idx = 0 ; idx < properties_.size() ; idx += 1) properties_[idx].type->destruct(buf); delete[]buf; } void class_type::set_vec4(class_type::inst_t obj, size_t pid, const vvp_vector4_t&val) const { char*buf = reinterpret_cast (obj); assert(pid < properties_.size()); properties_[pid].type->set_vec4(buf, val); } void class_type::get_vec4(class_type::inst_t obj, size_t pid, vvp_vector4_t&val) const { char*buf = reinterpret_cast (obj); assert(pid < properties_.size()); properties_[pid].type->get_vec4(buf, val); } void class_type::set_real(class_type::inst_t obj, size_t pid, double val) const { char*buf = reinterpret_cast (obj); assert(pid < properties_.size()); properties_[pid].type->set_real(buf, val); } double class_type::get_real(class_type::inst_t obj, size_t pid) const { char*buf = reinterpret_cast (obj); assert(pid < properties_.size()); return properties_[pid].type->get_real(buf); } void class_type::set_string(class_type::inst_t obj, size_t pid, const string&val) const { char*buf = reinterpret_cast (obj); assert(pid < properties_.size()); properties_[pid].type->set_string(buf, val); } string class_type::get_string(class_type::inst_t obj, size_t pid) const { char*buf = reinterpret_cast (obj); assert(pid < properties_.size()); return properties_[pid].type->get_string(buf); } void class_type::set_object(class_type::inst_t obj, size_t pid, const vvp_object_t&val, size_t idx) const { char*buf = reinterpret_cast (obj); assert(pid < properties_.size()); properties_[pid].type->set_object(buf, val, idx); } void class_type::get_object(class_type::inst_t obj, size_t pid, vvp_object_t&val, size_t idx) const { char*buf = reinterpret_cast (obj); assert(pid < properties_.size()); properties_[pid].type->get_object(buf, val, idx); } void class_type::copy_property(class_type::inst_t dst, size_t pid, class_type::inst_t src) const { char*dst_buf = reinterpret_cast (dst); char*src_buf = reinterpret_cast (src); assert(pid < properties_.size()); properties_[pid].type->copy(dst_buf, src_buf); } int class_type::get_type_code(void) const { return vpiClassDefn; } static class_type*compile_class = 0; void compile_class_start(char*lab, char*nam, unsigned ntype) { assert(compile_class == 0); compile_class = new class_type(nam, ntype); compile_vpi_symbol(lab, compile_class); free(lab); delete[]nam; } void compile_class_property(unsigned idx, char*nam, char*typ, uint64_t array_size) { assert(compile_class); compile_class->set_property(idx, nam, typ, array_size); delete[]nam; delete[]typ; } void compile_class_done(void) { __vpiScope*scope = vpip_peek_current_scope(); assert(scope); assert(compile_class); compile_class->finish_setup(); scope->classes[compile_class->class_name()] = compile_class; compile_class = 0; } #ifdef CHECK_WITH_VALGRIND void class_def_delete(class_type *item) { delete item; } #endif