From 0c72dfe60f6a2a71cf74c4b12821b43cdfc21690 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 17 Nov 2010 20:00:23 -0800 Subject: [PATCH] Initial implementation of $ivl_method$next/prev Create the v2009.vpi module to include SystemVerilog core functions, and start out with some of the enum methods. Add to vvp support for creating enum types, including some vpi access methods. --- .gitignore | 4 + sv_vpi_user.h | 7 ++ vpi/Makefile.in | 18 ++++- vpi/v2009.sft | 5 ++ vpi/v2009_enum.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++ vpi/v2009_table.c | 31 ++++++++ vvp/Makefile.in | 3 +- vvp/compile.h | 3 + vvp/enum_type.cc | 145 +++++++++++++++++++++++++++++++++++ vvp/enum_type.h | 22 ++++++ vvp/lexor.lex | 1 + vvp/parse.y | 42 ++++++++++- vvp/parse_misc.h | 5 ++ vvp/vvp_net.cc | 18 +++++ vvp/vvp_net.h | 2 + 15 files changed, 487 insertions(+), 6 deletions(-) create mode 100644 vpi/v2009.sft create mode 100644 vpi/v2009_enum.c create mode 100644 vpi/v2009_table.c create mode 100644 vvp/enum_type.cc create mode 100644 vvp/enum_type.h diff --git a/.gitignore b/.gitignore index 538236514..21e8b33cb 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,9 @@ # Object files and libraries *.[oa] +gmon*.out +gmon*.txt + # From autoconf configure config.log @@ -54,6 +57,7 @@ dep /vpi/sdf_parse.output /vpi/sys_readmem_lex.c +/vvp/dump.* /vvp/lexor.cc /vvp/parse.cc /vvp/parse.h diff --git a/sv_vpi_user.h b/sv_vpi_user.h index d06c16689..d613f1185 100644 --- a/sv_vpi_user.h +++ b/sv_vpi_user.h @@ -49,6 +49,13 @@ EXTERN_C_START #define vpiByteVar 614 #define vpiLogicVar vpiReg +/********* TYPESPECS *************/ +#define vpiEnumTypespec 633 +#define vpiEnumConst 634 + +/********* Many-to-One ***********/ +#define vpiMember 742 + EXTERN_C_END #endif diff --git a/vpi/Makefile.in b/vpi/Makefile.in index a9720dbd7..d57f6c1ef 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -73,7 +73,9 @@ M = sys_clog2.o v2005_math.o # Object files for va_math.vpi V = va_math.o -all: dep system.vpi va_math.vpi v2005_math.vpi $(ALL32) +V2009 = v2009_table.o v2009_enum.o + +all: dep system.vpi va_math.vpi v2005_math.vpi v2009.vpi $(ALL32) check: all @@ -128,6 +130,9 @@ sdf_parse.c sdf_parse.h: $(srcdir)/sdf_parse.y v2005_math.vpi: $M ../vvp/libvpi.a $(CC) @shared@ -o $@ $M -L../vvp $(LDFLAGS) -lvpi $(VA_MATH_VPI_LDFLAGS) +v2009.vpi: $(V2009) ../vvp/libvpi.a + $(CC) @shared@ -o $@ $(V2009) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS) + va_math.vpi: $V ../vvp/libvpi.a $(CC) @shared@ -o $@ $V -L../vvp $(LDFLAGS) -lvpi $(VA_MATH_VPI_LDFLAGS) @@ -139,7 +144,8 @@ vpi_config.h: stamp-vpi_config-h install: all installdirs \ $(vpidir)/system.vpi $(vpidir)/system.sft \ $(vpidir)/va_math.vpi $(vpidir)/va_math.sft \ - $(vpidir)/v2005_math.vpi $(vpidir)/v2005_math.sft + $(vpidir)/v2005_math.vpi $(vpidir)/v2005_math.sft \ + $(vpidir)/v2009.vpi $(vpidir)/v2009.sft \ $(vpidir)/system.vpi: ./system.vpi $(INSTALL_PROGRAM) ./system.vpi "$(DESTDIR)$(vpidir)/system.vpi" @@ -159,6 +165,12 @@ $(vpidir)/v2005_math.vpi: ./v2005_math.vpi $(vpidir)/v2005_math.sft: v2005_math.sft $(INSTALL_DATA) $< "$(DESTDIR)$@" +$(vpidir)/v2009_math.vpi: ./v2009.vpi + $(INSTALL_PROGRAM) ./v2009.vpi "$(DESTDIR)$(vpidir)/v2009.vpi" + +$(vpidir)/v2009.sft: v2009.sft + $(INSTALL_DATA) $< "$(DESTDIR)$@" + installdirs: $(srcdir)/../mkinstalldirs $(srcdir)/../mkinstalldirs "$(DESTDIR)$(libdir)" "$(DESTDIR)$(vpidir)" @@ -169,6 +181,8 @@ uninstall: rm -f "$(DESTDIR)$(vpidir)/va_math.sft" rm -f "$(DESTDIR)$(vpidir)/v2005_math.vpi" rm -f "$(DESTDIR)$(vpidir)/v2005_math.sft" + rm -f "$(DESTDIR)$(vpidir)/v2009.vpi" + rm -f "$(DESTDIR)$(vpidir)/v2009.sft" -include $(patsubst %.o, dep/%.d, $O) -include $(patsubst %.o, dep/%.d, $(OPP)) diff --git a/vpi/v2009.sft b/vpi/v2009.sft new file mode 100644 index 000000000..a606d187d --- /dev/null +++ b/vpi/v2009.sft @@ -0,0 +1,5 @@ +# +# This is the system function descriptor table for the +# builtin (system) functions. +# + diff --git a/vpi/v2009_enum.c b/vpi/v2009_enum.c new file mode 100644 index 000000000..bcb8e80df --- /dev/null +++ b/vpi/v2009_enum.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2010 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "vpi_config.h" +# include "sv_vpi_user.h" +# include + +static void missing_arguments(vpiHandle sys) +{ + vpi_printf("%s:%d: error: Invalid/missing arguments next/prev method\n", + vpi_get_str(vpiFile, sys), vpi_get(vpiLineNo,sys)); + vpi_control(vpiFinish, 1); +} + +static PLI_INT32 ivl_method_next_prev_compiletf(ICARUS_VPI_CONST PLI_BYTE8*data) +{ + vpiHandle sys = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, sys); + vpiHandle arg_enum, arg_item, arg_extra; + + if (argv == 0) { + missing_arguments(sys); + return 0; + } + + arg_enum = vpi_scan(argv); + if (arg_enum == 0) { + missing_arguments(sys); + return 0; + } + + arg_item = vpi_scan(argv); + if (arg_item == 0) { + missing_arguments(sys); + return 0; + } + + /* Make sure there are no excess arguments */ + arg_extra = vpi_scan(argv); + if (arg_extra != 0) { + missing_arguments(sys); + vpi_free_object(argv); + return 0; + } + + /* The first argument must be an enum typespec */ + if (vpi_get(vpiType, arg_enum) != vpiEnumTypespec) { + missing_arguments(sys); + return 0; + } + + /* The return value and input value must be the same size */ + if (vpi_get(vpiSize,sys) != vpi_get(vpiSize,arg_item)) { + missing_arguments(sys); + return 0; + } + return 0; +} + +static PLI_INT32 ivl_method_next2_calltf(PLI_BYTE8*data) +{ + vpiHandle sys = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, sys); + vpiHandle arg_enum = vpi_scan(argv); + vpiHandle arg_item = vpi_scan(argv); + vpiHandle arg_extra = vpi_scan(argv); + + vpiHandle enum_list = 0; + vpiHandle memb = 0, first_memb = 0; + + s_vpi_value memb_value, item_value; + + assert(arg_extra == 0); + + item_value.format = vpiIntVal; + vpi_get_value(arg_item, &item_value); + + enum_list = vpi_iterate(vpiMember, arg_enum); + assert(enum_list); + + /* Search for the current value in the member list. */ + do { + memb = vpi_scan(enum_list); + if (first_memb == 0) first_memb = memb; + if (memb == 0) break; + memb_value.format = vpiIntVal; + vpi_get_value(memb, &memb_value); + } while (memb_value.value.integer != item_value.value.integer); + + if (memb != 0); + memb = vpi_scan(enum_list); + + if (memb != 0) + vpi_free_object(enum_list); + + if (memb == 0) { + memb = first_memb; + memb_value.format = vpiIntVal; + } + + vpi_get_value(memb, &memb_value); + vpi_put_value(sys, &memb_value, 0, vpiNoDelay); + + return 0; +} + +static PLI_INT32 ivl_method_prev2_calltf(PLI_BYTE8*data) +{ + vpiHandle sys = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, sys); + vpiHandle arg_enum = vpi_scan(argv); + vpiHandle arg_item = vpi_scan(argv); + vpiHandle arg_extra = vpi_scan(argv); + + vpiHandle enum_list = 0; + vpiHandle memb = 0, prev = 0, last_memb = 0; + + s_vpi_value memb_value, item_value; + + assert(arg_extra == 0); + + item_value.format = vpiIntVal; + vpi_get_value(arg_item, &item_value); + + enum_list = vpi_iterate(vpiMember, arg_enum); + assert(enum_list); + + /* Search for the current value in the member list. */ + do { + prev = memb; + memb = vpi_scan(enum_list); + if (memb == 0) break; + last_memb = memb; + memb_value.format = vpiIntVal; + vpi_get_value(memb, &memb_value); + } while (memb_value.value.integer != item_value.value.integer); + + while (memb) { + last_memb = memb; + memb = vpi_scan(enum_list); + } + + if (prev == 0) + prev = last_memb; + + vpi_get_value(prev, &memb_value); + vpi_put_value(sys, &memb_value, 0, vpiNoDelay); + + return 0; +} + +void v2009_enum_register(void) +{ + s_vpi_systf_data tf_data; + + tf_data.type = vpiSysFunc; + tf_data.calltf = ivl_method_next2_calltf; + tf_data.compiletf = ivl_method_next_prev_compiletf; + tf_data.sizetf = 0; + tf_data.tfname = "$ivl_method$next"; + tf_data.user_data = "$ivl_method$next"; + vpi_register_systf(&tf_data); + + tf_data.type = vpiSysFunc; + tf_data.calltf = ivl_method_prev2_calltf; + tf_data.compiletf = 0; + tf_data.sizetf = 0; + tf_data.tfname = "$ivl_method$prev"; + tf_data.user_data = "$ivl_method$prev"; + vpi_register_systf(&tf_data); +} diff --git a/vpi/v2009_table.c b/vpi/v2009_table.c new file mode 100644 index 000000000..be21785d3 --- /dev/null +++ b/vpi/v2009_table.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2010 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "vpi_config.h" +# include "vpi_user.h" +# include +# include +# include + +extern void v2009_enum_register(void); + +void (*vlog_startup_routines[])() = { + v2009_enum_register, + 0 +}; diff --git a/vvp/Makefile.in b/vvp/Makefile.in index b5be44e01..d959f14c3 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -67,7 +67,8 @@ V = vpi_modules.o vpi_callback.o vpi_const.o vpi_event.o vpi_iter.o vpi_mcd.o \ vpip_to_dec.o vpip_format.o vvp_vpi.o O = main.o parse.o parse_misc.o lexor.o arith.o array.o bufif.o compile.o \ - concat.o dff.o extend.o npmos.o part.o permaheap.o reduce.o resolv.o \ + concat.o dff.o enum_type.o extend.o npmos.o part.o permaheap.o \ + reduce.o resolv.o \ sfunc.o stop.o symbols.o ufunc.o codes.o vthread.o schedule.o \ statistics.o tables.o udp.o vvp_island.o vvp_net.o vvp_net_sig.o \ event.o logic.o delay.o words.o island_tran.o $V diff --git a/vvp/compile.h b/vvp/compile.h index 4eaa051a5..43edf40fb 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -21,6 +21,7 @@ # include # include +# include # include # include "parse_misc.h" # include "sv_vpi_user.h" @@ -201,6 +202,8 @@ extern void compile_dff(char*label, struct symb_s arg_e, struct symb_s arg_a); +extern void compile_enum_type(char*label, std::list*names); + class __vpiModPath; extern __vpiModPath* compile_modpath(char*label, unsigned width, diff --git a/vvp/enum_type.cc b/vvp/enum_type.cc new file mode 100644 index 000000000..06aefca48 --- /dev/null +++ b/vvp/enum_type.cc @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2010 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "compile.h" +# include "enum_type.h" +# include +# include + +struct enumconst_s { + struct __vpiHandle base; + const char*name; + vvp_vector2_t val2; +}; + +static struct enumconst_s* enumconst_from_handle(vpiHandle obj) +{ + if (obj->vpi_type->type_code == vpiEnumConst) + return (struct enumconst_s*) obj; + else + return 0; +} + +struct __vpiEnumTypespec { + struct __vpiHandle base; + std::vector names; +}; + +static struct __vpiEnumTypespec* vpip_enum_typespec_from_handle(vpiHandle obj) +{ + if (obj->vpi_type->type_code == vpiEnumTypespec) + return (struct __vpiEnumTypespec*) obj; + + return 0; +} + +static vpiHandle enum_type_iterate(int code, vpiHandle obj) +{ + struct __vpiEnumTypespec*ref = vpip_enum_typespec_from_handle(obj); + assert(ref); + + if (code == vpiMember) { + vpiHandle*args = (vpiHandle*) + calloc(ref->names.size(), sizeof(vpiHandle*)); + for (int idx = 0 ; idx < ref->names.size() ; idx += 1) + args[idx] = vpi_handle(&ref->names[idx]); + + return vpip_make_iterator(ref->names.size(), args, true); + } + + return 0; +} + +static const struct __vpirt enum_type_rt = { + vpiEnumTypespec, + 0, //enum_type_get, + 0, //enum_type_get_str, + 0, //enum_type_get_value, + 0, //enum_type_put_value, + 0, //enum_type_handle, + enum_type_iterate, + 0, //enum_type_index, + 0, //enum_type_free_object, + 0, //enum_type_get_delays, + 0, //enum_type_put_delays +}; + +static char* enum_name_get_str(int code, vpiHandle obj) +{ + struct enumconst_s*ref = enumconst_from_handle(obj); + assert(ref); + + switch (code) { + case vpiName: + return const_cast (ref->name); + default: + return 0; + } +} + +static void enum_name_get_value(vpiHandle obj, p_vpi_value value) +{ + struct enumconst_s*ref = enumconst_from_handle(obj); + assert(ref); + + switch (value->format) { + case vpiObjTypeVal: + value->format = vpiIntVal; + case vpiIntVal: + vector2_to_value(ref->val2, value->value.integer, true); + break; + default: + break; + } +} + +static const struct __vpirt enum_name_rt = { + vpiEnumConst, + 0, //enum_name_get, + enum_name_get_str, + enum_name_get_value, + 0, //enum_name_put_value, + 0, //enum_name_handle, + 0, //enum_name_iterate, + 0, //enum_name_index, + 0, //enum_name_free_object, + 0, //enum_name_get_delays, + 0, //enum_name_put_delays +}; + +void compile_enum_type(char*label, std::list*names) +{ + struct __vpiEnumTypespec*spec = new struct __vpiEnumTypespec; + spec->base.vpi_type = &enum_type_rt; + spec->names = std::vector (names->size()); + + size_t idx = 0; + for (list::iterator cur = names->begin() + ; cur != names->end() ; ++cur, ++idx) { + spec->names[idx].base.vpi_type = &enum_name_rt; + spec->names[idx].name = cur->text; + spec->names[idx].val2 = vvp_vector2_t(cur->val2, 32); + } + + assert(idx == spec->names.size()); + compile_vpi_symbol(label, vpi_handle(spec)); + + free(label); + delete names; +} diff --git a/vvp/enum_type.h b/vvp/enum_type.h new file mode 100644 index 000000000..78464aab3 --- /dev/null +++ b/vvp/enum_type.h @@ -0,0 +1,22 @@ +#ifndef __enum_type_H +#define __enum_type_H +/* + * Copyright (c) 2010 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#endif diff --git a/vvp/lexor.lex b/vvp/lexor.lex index 6dfee86a1..2736cb765 100644 --- a/vvp/lexor.lex +++ b/vvp/lexor.lex @@ -142,6 +142,7 @@ static char* strdupnew(char const *str) ".concat" { return K_CONCAT; } ".delay" { return K_DELAY; } ".dff" { return K_DFF; } +".enum" { return K_ENUM; } ".event" { return K_EVENT; } ".event/or" { return K_EVENT_OR; } ".export" { return K_EXPORT; } diff --git a/vvp/parse.y b/vvp/parse.y index a77ead1ee..c9936c97d 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -23,6 +23,7 @@ # include "compile.h" # include "delay.h" # include "ivl_alloc.h" +# include # include # include # include @@ -58,6 +59,9 @@ static struct __vpiModPath*modpath_dst = 0; struct numbv_s numbv; + struct enum_name_s enum_name; + std::list*enum_namev; + struct symb_s vect; struct argv_s argv; @@ -76,7 +80,7 @@ static struct __vpiModPath*modpath_dst = 0; %token K_CMP_EEQ K_CMP_EQ K_CMP_EQ_R K_CMP_NEE K_CMP_NE K_CMP_NE_R %token K_CMP_GE K_CMP_GE_R K_CMP_GE_S K_CMP_GT K_CMP_GT_R K_CMP_GT_S %token K_CONCAT K_DEBUG K_DELAY K_DFF -%token K_EVENT K_EVENT_OR K_EXPORT K_EXTEND_S K_FUNCTOR K_IMPORT K_ISLAND +%token K_ENUM K_EVENT K_EVENT_OR K_EXPORT K_EXTEND_S K_FUNCTOR K_IMPORT K_ISLAND %token K_MODPATH %token K_NET K_NET_S K_NET_R K_NET_2S K_NET_2U K_NET8 K_NET8_S %token K_PARAM_STR K_PARAM_L K_PARAM_REAL K_PART K_PART_PV @@ -112,6 +116,9 @@ static struct __vpiModPath*modpath_dst = 0; %type argument symbol_access %type delay +%type enum_type_name +%type enum_type_names + %% source_file : header_lines_opt program footer_lines; @@ -780,10 +787,39 @@ statement | K_TRANVP T_NUMBER T_NUMBER T_NUMBER ',' T_SYMBOL ',' T_SYMBOL T_SYMBOL ';' { compile_island_tranvp($6, $8, $9, $2, $3, $4); } + /* Other statemehts */ + + | enum_type + { ; } + /* Oh and by the way, empty statements are OK as well. */ - | ';' - ; + | ';' + ; + + /* Enumeration types */ +enum_type + : T_LABEL K_ENUM enum_type_names ';' + { compile_enum_type($1, $3); } + ; + +enum_type_names + : enum_type_name + { list*tmp = new list; + tmp->push_back($1); + $$ = tmp; + } + | enum_type_names ',' enum_type_name + { list*tmp = $1; + tmp->push_back($3); + $$ = tmp; + } + ; + +enum_type_name + : T_STRING T_NUMBER + { $$.text = $1; $$.val2 = $2; } + ; local_flag : '*' { $$ = true; } diff --git a/vvp/parse_misc.h b/vvp/parse_misc.h index 85c01240b..81c8d00fe 100644 --- a/vvp/parse_misc.h +++ b/vvp/parse_misc.h @@ -70,6 +70,11 @@ struct numbv_s { long*nvec; }; +struct enum_name_s { + char*text; + uint64_t val2; +}; + extern void numbv_init(struct numbv_s*obj); extern void numbv_add(struct numbv_s*obj, long item); extern void numbv_clear(struct numbv_s*obj); diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index a1a5acc75..27788c3c4 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -1697,6 +1697,24 @@ bool vector4_to_value(const vvp_vector4_t&vec, double&val, bool signed_flag) return flag; } +bool vector2_to_value(const vvp_vector2_t&a, int32_t&val, bool is_signed) +{ + val = 0; + int idx; + int32_t mask; + for (idx = 0, mask = 1 ; idx < a.size() && idx < 32 ; idx += 1, mask <<= 1) { + if (a.value(idx)) val |= mask; + } + + if (is_signed && a.size() < 32 && a.value(a.size()-1)) { + mask = -1; + mask <<= a.size(); + val |= mask; + } + + return a.size() <= 32; +} + vvp_realarray_t::vvp_realarray_t(unsigned wor) : words_(wor) { diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index aa531b8af..1e58d6df5 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -496,6 +496,8 @@ extern bool vector4_to_value(const vvp_vector4_t&a, vvp_time64_t&val); #endif extern bool vector4_to_value(const vvp_vector4_t&a, double&val, bool is_signed); +extern bool vector2_to_value(const vvp_vector2_t&a, int32_t&val, bool is_signed); + /* * The __vpiArray handle uses instances of this to keep an array of * real valued variables.