Merge pull request #49 from orsonmmz/darray_vpi

Support for dynamic arrays in the VPI
This commit is contained in:
Stephen Williams 2014-12-01 17:12:57 -08:00
commit f3ba335493
23 changed files with 1346 additions and 827 deletions

View File

@ -146,6 +146,15 @@ PECastSize::~PECastSize()
{
}
PECastType::PECastType(data_type_t*t, PExpr*b)
: target_(t), base_(b)
{
}
PECastType::~PECastType()
{
}
PEBComp::PEBComp(char op, PExpr*l, PExpr*r)
: PEBinary(op, l, r)
{

22
PExpr.h
View File

@ -986,6 +986,28 @@ class PECastSize : public PExpr {
PExpr* base_;
};
/*
* Support the SystemVerilog cast to a different type.
*/
class PECastType : public PExpr {
public:
explicit PECastType(data_type_t*target, PExpr*base);
~PECastType();
void dump(ostream &out) const;
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
unsigned expr_wid, unsigned flags) const;
virtual unsigned test_width(Design*des, NetScope*scope,
width_mode_t&mode);
private:
data_type_t* target_;
PExpr* base_;
};
/*
* This class is used for error recovery. All methods do nothing and return
* null or default values.

View File

@ -36,6 +36,7 @@
# include "netmisc.h"
# include "netdarray.h"
# include "netstruct.h"
# include "netscalar.h"
# include "util.h"
# include "ivl_assert.h"
@ -2431,6 +2432,87 @@ NetExpr* PECastSize::elaborate_expr(Design*des, NetScope*scope,
return sel;
}
unsigned PECastType::test_width(Design*des, NetScope*scope, width_mode_t&wid)
{
ivl_type_t t = target_->elaborate_type(des, scope);
base_->test_width(des, scope, wid);
if(const netdarray_t*use_darray = dynamic_cast<const netdarray_t*> (t)) {
expr_type_ = use_darray->element_base_type();
expr_width_ = use_darray->element_width();
}
else if(const netstring_t*use_string = dynamic_cast<const netstring_t*> (t)) {
expr_type_ = use_string->base_type();
expr_width_ = 8;
}
else {
expr_type_ = t->base_type();
expr_width_ = t->packed_width();
}
signed_flag_= t->get_signed();
min_width_ = expr_width_;
return expr_width_;
}
NetExpr* PECastType::elaborate_expr(Design*des, NetScope*scope,
unsigned, unsigned) const
{
NetExpr*expr = base_->elaborate_expr(des, scope, base_->expr_width(), NO_FLAGS);
if(dynamic_cast<const real_type_t*>(target_)) {
return cast_to_real(expr);
}
if(const atom2_type_t*atom = dynamic_cast<const atom2_type_t*>(target_)) {
if(base_->expr_width() > expr_width_) {
cerr << get_fileline() << ": cast type is not wide enough to store the result." << endl;
ivl_assert(*this, 0);
}
if(base_->has_sign() != atom->signed_flag) {
cerr << get_fileline() << ": cast type and subject differ in signedness." << endl;
ivl_assert(*this, 0);
}
// That is how you both resize & cast to integers
return new NetECast('2', expr, expr_width_, expr->has_sign());
}
if(const vector_type_t*vec = dynamic_cast<const vector_type_t*>(target_)) {
switch(vec->base_type) {
case IVL_VT_BOOL:
return cast_to_int2(expr, expr_width_);
case IVL_VT_LOGIC:
return cast_to_int4(expr, expr_width_);
default:
break; /* Suppress warnings */
}
}
else if(dynamic_cast<const string_type_t*>(target_)) {
if(base_->expr_type() == IVL_VT_STRING)
return expr; // no conversion
if((base_->expr_type() != IVL_VT_BOOL) &&
(base_->expr_type() != IVL_VT_LOGIC)) {
cerr << get_fileline() << ": cannot be casted to string." << endl;
ivl_assert(*this, false);
}
return expr;
}
cerr << get_fileline() << ": sorry: I don't know how to cast expression." << endl;
ivl_assert(*this, false);
return expr;
}
unsigned PEConcat::test_width(Design*des, NetScope*scope, width_mode_t&)
{
expr_width_ = 0;
@ -4942,6 +5024,18 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
return res;
}
if (net->sig()->data_type() == IVL_VT_STRING) {
// Special case: This is a select of a string.
// This should be interpreted as a byte select.
if (debug_elaborate) {
cerr << get_fileline() << ": debug: "
<< "Bit select of a string becomes NetESelect." << endl;
}
NetESelect*res = new NetESelect(net, mux, 8);
res->set_line(*net);
return res;
}
// Non-constant bit select? punt and make a subsignal
// device to mux the bit in the net. This is a fairly
// complicated task because we need to generate

12
parse.y
View File

@ -3543,6 +3543,18 @@ expr_primary
}
}
| data_type '\'' '(' expression ')'
{ PExpr*base = $4;
if (gn_system_verilog()) {
PECastType*tmp = new PECastType($1, base);
FILE_NAME(tmp, @1);
$$ = tmp;
} else {
yyerror(@1, "error: Type cast requires SystemVerilog.");
$$ = base;
}
}
/* Aggregate literals are primaries. */
| assignment_pattern

View File

@ -2239,7 +2239,7 @@ void pform_make_reginit(const struct vlltype&li,
PEIdent*lval = new PEIdent(name);
FILE_NAME(lval, li);
PAssign*ass = new PAssign(lval, expr, true);
PAssign*ass = new PAssign(lval, expr, generation_flag < GN_VER2001);
FILE_NAME(ass, li);
PProcess*top = new PProcess(IVL_PR_INITIAL, ass);
FILE_NAME(top, li);

View File

@ -323,6 +323,14 @@ void PECastSize::dump(ostream &out) const
out << ")";
}
void PECastType::dump(ostream &out) const
{
target_->pform_dump(out, 0);
out << "'(";
base_->dump(out);
out << ")";
}
void PEEvent::dump(ostream&out) const
{
switch (type_) {

View File

@ -193,6 +193,17 @@ int load_sys_func_table(const char*path)
continue;
}
if (strcmp(stype,"vpiSysFuncVoid") == 0) {
cell = new struct sfunc_return_type_cell;
cell->name = lex_strings.add(name);
cell->type = IVL_VT_VOID;
cell->wid = 0;
cell->signed_flag = false;
cell->next = sfunc_stack;
sfunc_stack = cell;
continue;
}
fprintf(stderr, "%s:%s: Unknown type: %s\n",
path, name, stype);
}

View File

@ -593,6 +593,14 @@ static int show_stmt_assign_vector(ivl_statement_t net)
fprintf(vvp_out, " %%cvt/vr %u, %u;\n", res.base, res.wid);
} else if (ivl_expr_value(rval) == IVL_VT_STRING) {
/* Special case: vector to string casting */
ivl_lval_t lval = ivl_stmt_lval(net, 0);
fprintf(vvp_out, " %%vpi_call %u %u \"$ivl_string_method$to_vec\", v%p_0, v%p_0 {0 0};\n",
ivl_file_table_index(ivl_stmt_file(net)), ivl_stmt_lineno(net),
ivl_expr_signal(rval), ivl_lval_sig(lval));
return 0;
} else {
res = draw_eval_expr(rval, 0);
}

View File

@ -22,4 +22,5 @@ $simparam vpiSysFuncReal
$simparam$str vpiSysFuncSized 1024 unsigned
$table_model vpiSysFuncReal
$ivl_string_method$len vpiSysFuncInt
$ivl_string_method$len vpiSysFuncInt
$ivl_string_method$to_vec vpiSysFuncVoid

View File

@ -19,6 +19,9 @@
# include "sys_priv.h"
# include <assert.h>
# include <math.h>
# include <stdlib.h>
# include <string.h>
static PLI_INT32 one_string_arg_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
@ -75,6 +78,120 @@ static PLI_INT32 len_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
return 0;
}
static PLI_INT32 to_vec_compiletf(ICARUS_VPI_CONST PLI_BYTE8*user_data)
{
(void) user_data; /* Parameter is not used. */
vpiHandle systf_handle, arg_iterator, arg_handle;
PLI_INT32 arg_type[2];
/* obtain a handle to the system task instance */
systf_handle = vpi_handle(vpiSysTfCall, NULL);
if (systf_handle == NULL) {
vpi_printf("ERROR: $ivl_string_method$to_vec failed to obtain systf handle\n");
vpi_control(vpiFinish,0); /* abort simulation */
return 0;
}
/* obtain handles to system task arguments */
arg_iterator = vpi_iterate(vpiArgument, systf_handle);
if (arg_iterator == NULL) {
vpi_printf("ERROR: $ivl_string_method$to_vec requires 2 arguments\n");
vpi_control(vpiFinish, 0);
return 0;
}
/* check the type of object in system task arguments */
arg_handle = vpi_scan(arg_iterator);
for(int i = 0; i < 2; ++i) {
arg_type[i] = vpi_get(vpiType, arg_handle);
arg_handle = vpi_scan(arg_iterator);
}
if (arg_handle != NULL) { /* are there more arguments? */
vpi_printf("ERROR: $ivl_string_method$to_vec can only have 2 arguments\n");
vpi_free_object(arg_iterator);
vpi_control(vpiFinish, 0);
return 0;
}
if ((arg_type[0] != vpiStringVar) ||
(arg_type[1] != vpiNet && arg_type[1] != vpiReg)) {
vpi_printf("ERROR: $ivl_string_method$to_vec value arguments must be a string and a net or reg\n");
vpi_free_object(arg_iterator);
vpi_control(vpiFinish, 0);
return 0;
}
return 0;
}
static PLI_INT32 to_vec_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
(void)name; /* Parameter is not used. */
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv, str, vec;
s_vpi_value str_val;
s_vpi_vecval*vec_val;
/* Fetch arguments */
argv = vpi_iterate(vpiArgument, callh);
assert(argv);
str = vpi_scan(argv);
assert(str);
vec = vpi_scan(argv);
assert(vec);
vpi_free_object(argv);
int str_size = vpi_get(vpiSize, str);
int vec_size = vpi_get(vpiSize, vec);
if(str_size <= 0) {
vpi_printf("ERROR: Cannot cast empty string");
vpi_control(vpiFinish, 0);
return 0;
}
if(vec_size != str_size * 8) {
vpi_printf("ERROR: String and vector size do not match");
vpi_control(vpiFinish, 0);
return 0;
}
str_val.format = vpiStringVal;
vpi_get_value(str, &str_val);
assert(str_val.value.str);
/* Conversion part */
int vec_number = ceil((double)str_size / sizeof(PLI_INT32));
vec_val = calloc(vec_number, sizeof(s_vpi_vecval));
PLI_BYTE8*str_ptr = &str_val.value.str[str_size - 1];
/* We have to reverse the order of string, no memcpy here */
for(int i = 0; i < vec_number; ++i) {
int copy_size = str_size > (int)sizeof(PLI_INT32) ?
(int)sizeof(PLI_INT32) : str_size;
/* Clear the part responsible for X & Z values */
memset(&vec_val[i].bval, 0x00, sizeof(PLI_INT32));
PLI_BYTE8*dest = (PLI_BYTE8*)&vec_val[i].aval;
for(int j = 0; j < copy_size; ++j)
*dest++ = *str_ptr--;
str_size -= copy_size;
}
str_val.format = vpiVectorVal;
str_val.value.vector = vec_val;
vpi_put_value(vec, &str_val, 0, vpiNoDelay);
free(vec_val);
return 0;
}
void v2009_string_register(void)
{
s_vpi_systf_data tf_data;
@ -89,4 +206,14 @@ void v2009_string_register(void)
tf_data.user_data = "$ivl_string_method$len";
res = vpi_register_systf(&tf_data);
vpip_make_systf_system_defined(res);
tf_data.type = vpiSysTask;
tf_data.sysfunctype = 0;
tf_data.tfname = "$ivl_string_method$to_vec";
tf_data.calltf = to_vec_calltf;
tf_data.compiletf = to_vec_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$ivl_string_method$to_vec";
res = vpi_register_systf(&tf_data);
vpip_make_systf_system_defined(res);
}

View File

@ -71,7 +71,7 @@ V = vpi_modules.o vpi_callback.o vpi_cobject.o vpi_const.o vpi_darray.o \
vpi_vthr_vector.o vpip_bin.o vpip_hex.o vpip_oct.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 \
O = main.o parse.o parse_misc.o lexor.o arith.o array_common.o array.o bufif.o compile.o \
concat.o dff.o class_type.o enum_type.o extend.o file_line.o npmos.o part.o \
permaheap.o reduce.o resolv.o \
sfunc.o stop.o \

File diff suppressed because it is too large Load Diff

View File

@ -30,31 +30,8 @@ class value_callback;
* table of all the arrays in the design.
*/
extern vvp_array_t array_find(const char*label);
extern unsigned get_array_word_size(vvp_array_t array);
extern vpiHandle array_index_iterate(int code, vpiHandle ref);
extern void array_word_change(vvp_array_t array, unsigned long addr);
extern void array_attach_word(vvp_array_t array, unsigned addr, vpiHandle word);
extern void array_alias_word(vvp_array_t array, unsigned long addr,
vpiHandle word, int msb, int lsb);
extern void array_set_word(vvp_array_t arr, unsigned idx,
unsigned off, vvp_vector4_t val);
extern void array_set_word(vvp_array_t arr, unsigned idx,
double val);
extern void array_set_word(vvp_array_t arr, unsigned idx,
const std::string&val);
extern void array_set_word(vvp_array_t arr, unsigned idx,
const vvp_object_t&val);
extern vvp_vector4_t array_get_word(vvp_array_t array, unsigned address);
extern double array_get_word_r(vvp_array_t array, unsigned address);
extern void array_get_word_obj(vvp_array_t array, unsigned address, vvp_object_t&val);
extern std::string array_get_word_str(vvp_array_t array, unsigned address);
/* VPI hooks */
extern value_callback* vpip_array_word_change(p_cb_data data);
extern value_callback* vpip_array_change(p_cb_data data);

203
vvp/array_common.cc Normal file
View File

@ -0,0 +1,203 @@
/*
* Copyright (c) 2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 2014 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 "array_common.h"
vpiHandle __vpiArrayBase::vpi_array_base_iterate(int code)
{
switch (code) {
case vpiReg:
case vpiMemoryWord: {
struct __vpiArrayIterator*res;
res = new __vpiArrayIterator;
res->array = this;
res->next = 0;
return res;
}
}
return 0;
}
void __vpiArrayBase::make_vals_words()
{
assert(vals_words == 0);
vals_words = new struct __vpiArrayWord[get_size() + 1];
// Make word[-1] point to the parent.
vals_words->parent = this;
// Now point to word-0
vals_words += 1;
struct __vpiArrayWord*words = vals_words;
for (unsigned idx = 0 ; idx < get_size() ; idx += 1) {
words[idx].word0 = words;
}
}
vpiHandle __vpiArrayIterator::vpi_index(int)
{
if (next >= array->get_size()) {
vpi_free_object(this);
return 0;
}
unsigned use_index = next;
next += 1;
return array->get_iter_index(this, use_index);
}
static int array_iterator_free_object(vpiHandle ref)
{
struct __vpiArrayIterator*obj = dynamic_cast<__vpiArrayIterator*>(ref);
delete obj;
return 1;
}
__vpiHandle::free_object_fun_t __vpiArrayIterator::free_object_fun(void)
{ return &array_iterator_free_object; }
vpiHandle __vpiArrayIndex::vpi_iterate(int code)
{
// TODO originally, __vpiArrayIndex is casted to __vpiDecConst and assigned
// to res->index - seems like a bug to me
if (code == vpiIndex) {
struct __vpiArrayIndex*res;
res = new __vpiArrayIndex;
res->index = index; // see the comment above
res->done = 0;
return res;
}
return 0;
}
vpiHandle __vpiArrayIndex::vpi_index(int)
{
if (done == 0) {
done = 1;
return index;
}
vpi_free_object(this);
return 0;
}
static int array_index_free_object(vpiHandle ref)
{
struct __vpiArrayIndex*obj = dynamic_cast<__vpiArrayIndex*>(ref);
delete obj;
return 1;
}
__vpiHandle::free_object_fun_t __vpiArrayIndex::free_object_fun(void)
{ return &array_index_free_object; }
char* __vpiArrayWord::as_word_t::vpi_get_str(int code)
{
struct __vpiArrayWord*obj = array_var_word_from_handle(this);
assert(obj);
struct __vpiArrayBase*parent = obj->get_parent();
return parent->get_word_str(obj, code);
}
void __vpiArrayWord::as_word_t::vpi_get_value(p_vpi_value vp)
{
struct __vpiArrayWord*obj = array_var_word_from_handle(this);
assert(obj);
struct __vpiArrayBase*parent = obj->get_parent();
return parent->get_word_value(obj, vp);
}
vpiHandle __vpiArrayWord::as_word_t::vpi_put_value(p_vpi_value vp, int flags)
{
struct __vpiArrayWord*obj = array_var_word_from_handle(this);
assert(obj);
struct __vpiArrayBase*parent = obj->get_parent();
parent->put_word_value(obj, vp, flags);
return this;
}
vpiHandle __vpiArrayWord::as_word_t::vpi_handle(int code)
{
struct __vpiArrayWord*obj = array_var_word_from_handle(this);
assert(obj);
struct __vpiArrayBase*parent = obj->get_parent();
switch (code) {
case vpiIndex:
return &(obj->as_index);
case vpiLeftRange:
return parent->get_left_range();
case vpiRightRange:
return parent->get_right_range();
case vpiParent:
return dynamic_cast<vpiHandle>(parent);
case vpiScope:
return parent->get_scope();
case vpiModule:
return vpip_module(parent->get_scope());
}
return 0;
}
void __vpiArrayWord::as_index_t::vpi_get_value(p_vpi_value vp)
{
struct __vpiArrayWord*obj = array_var_index_from_handle(this);
assert(obj);
unsigned index = obj->get_index();
assert(vp->format == vpiIntVal);
vp->value.integer = index;
}
struct __vpiArrayWord*array_var_word_from_handle(vpiHandle ref)
{
if (ref == 0)
return 0;
__vpiArrayWord::as_word_t*ptr = dynamic_cast<__vpiArrayWord::as_word_t*> (ref);
if (ptr == 0)
return 0;
return (struct __vpiArrayWord*) ref;
}
struct __vpiArrayWord* array_var_index_from_handle(vpiHandle ref)
{
if (ref == 0)
return 0;
__vpiArrayWord::as_index_t*ptr = dynamic_cast<__vpiArrayWord::as_index_t*> (ref);
if (ptr == 0)
return 0;
assert(sizeof(__vpiHandle) == sizeof(__vpiArrayWord::as_index_t));
assert(sizeof(__vpiHandle) == sizeof(__vpiArrayWord::as_word_t));
return (struct __vpiArrayWord*) (ref-1);
}

98
vvp/array_common.h Normal file
View File

@ -0,0 +1,98 @@
/*
* Copyright (c) 2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 2014 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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.
*/
#ifndef ARRAY_COMMON_H
#define ARRAY_COMMON_H
#include "vpi_priv.h"
struct __vpiArrayIterator : public __vpiHandle {
int get_type_code(void) const
{ return vpiIterator; }
vpiHandle vpi_index(int idx);
free_object_fun_t free_object_fun(void);
struct __vpiArrayBase*array;
unsigned next;
};
struct __vpiArrayIndex : public __vpiHandle {
int get_type_code(void) const
{ return vpiIterator; }
vpiHandle vpi_iterate(int code);
vpiHandle vpi_index(int idx);
free_object_fun_t free_object_fun(void);
__vpiDecConst *index;
unsigned done;
};
/*
* The vpiArrayWord is magic. It is used as the handle to return when
* vpi code tries to index or scan an array of variable words. The
* array word handle contains no actual data. It is just a hook for
* the vpi methods and to point to the parent.
*
* How the point to the parent works is tricky. The vpiArrayWord
* objects for an array are themselves allocated as an array. All the
* ArrayWord objects in the array have a word0 that points to the base
* of the array. Thus, the position into the array (and the index into
* the memory) is calculated by subtracting word0 from the ArrayWord
* pointer.
*
* To then get to the parent, use word0[-1].parent.
*
* The vpiArrayWord is also used as a handle for the index (vpiIndex)
* for the word. To make that work, return the pointer to the as_index
* member instead of the as_word member. The result is a different set
* of vpi functions is bound to the same structure. All the details
* for the word also apply when treating this as an index.
*/
struct __vpiArrayWord {
struct as_word_t : public __vpiHandle {
int get_type_code(void) const { return vpiMemoryWord; }
int vpi_get(int code);
char*vpi_get_str(int code);
void vpi_get_value(p_vpi_value vp);
vpiHandle vpi_put_value(p_vpi_value vp, int flags);
vpiHandle vpi_handle(int code);
} as_word;
struct as_index_t : public __vpiHandle {
int get_type_code(void) const { return vpiIndex; }
void vpi_get_value(p_vpi_value val);
} as_index;
union {
struct __vpiArrayBase*parent;
struct __vpiArrayWord*word0;
};
inline unsigned get_index() const { return this - word0; }
inline struct __vpiArrayBase*get_parent() const { return (word0 - 1)->parent; }
};
struct __vpiArrayWord*array_var_word_from_handle(vpiHandle ref);
struct __vpiArrayWord*array_var_index_from_handle(vpiHandle ref);
#endif /* ARRAY_COMMON_H */

View File

@ -137,7 +137,7 @@ evctl_array::evctl_array(vvp_array_t memory, unsigned index,
void evctl_array::run_run()
{
array_set_word(mem_, idx_, off_, value_);
mem_->set_word(idx_, off_, value_);
}
void schedule_evctl(vvp_array_t memory, unsigned index,
@ -163,7 +163,7 @@ evctl_array_r::evctl_array_r(vvp_array_t memory, unsigned index,
void evctl_array_r::run_run()
{
array_set_word(mem_, idx_, value_);
mem_->set_word(idx_, value_);
}
void schedule_evctl(vvp_array_t memory, unsigned index,

View File

@ -306,7 +306,7 @@ struct assign_array_word_s : public event_s {
void assign_array_word_s::run_run(void)
{
count_assign_events += 1;
array_set_word(mem, adr, off, val);
mem->set_word(adr, off, val);
}
static const size_t ARRAY_W_CHUNK_COUNT = 8192 / sizeof(struct assign_array_word_s);
@ -396,7 +396,7 @@ struct assign_array_r_word_s : public event_s {
void assign_array_r_word_s::run_run(void)
{
count_assign_events += 1;
array_set_word(mem, adr, val);
mem->set_word(adr, val);
}
static const size_t ARRAY_R_W_CHUNK_COUNT = 8192 / sizeof(struct assign_array_r_word_s);
static slab_t<sizeof(assign_array_r_word_s),ARRAY_R_W_CHUNK_COUNT> array_r_w_heap;

View File

@ -688,7 +688,7 @@ void vvp_vpi_callback::clear_all_callbacks()
*/
void vvp_vpi_callback::run_vpi_callbacks()
{
if (array_) array_word_change(array_, array_word_);
if (array_) array_->word_change(array_word_);
value_callback *next = vpi_callbacks_;
value_callback *prev = 0;

View File

@ -22,6 +22,7 @@
# include "vpi_priv.h"
# include "vvp_net_sig.h"
# include "vvp_darray.h"
# include "array_common.h"
# include "schedule.h"
#ifdef CHECK_WITH_VALGRIND
# include "vvp_cleanup.h"
@ -39,42 +40,255 @@ __vpiDarrayVar::__vpiDarrayVar(__vpiScope*sc, const char*na, vvp_net_t*ne)
{
}
int __vpiDarrayVar::get_type_code(void) const
{ return vpiArrayVar; }
int __vpiDarrayVar::vpi_get(int code)
unsigned __vpiDarrayVar::get_size() const
{
vvp_fun_signal_object*fun = dynamic_cast<vvp_fun_signal_object*> (get_net()->fun);
assert(fun);
if(!fun)
return 0;
vvp_object_t val = fun->get_object();
vvp_darray*aval = val.peek<vvp_darray>();
if(!aval)
return 0;
return aval->get_size();
}
vpiHandle __vpiDarrayVar::get_left_range()
{
left_range_.set_value(0);
return &left_range_;
}
vpiHandle __vpiDarrayVar::get_right_range()
{
right_range_.set_value(get_size() - 1);
return &right_range_;
}
int __vpiDarrayVar::get_word_size() const
{
vvp_vector4_t new_vec;
vvp_darray*aobj = get_vvp_darray();
aobj->get_word(0, new_vec);
return new_vec.size();
}
char*__vpiDarrayVar::get_word_str(struct __vpiArrayWord*word, int code)
{
unsigned index = word->get_index();
if (code == vpiFile) { // Not implemented for now!
return simple_set_rbuf_str(file_names[0]);
}
char sidx [64];
snprintf(sidx, 63, "%d", (int)index);
return generic_get_str(code, scope_, name_, sidx);
}
void __vpiDarrayVar::get_word_value(struct __vpiArrayWord*word, p_vpi_value vp)
{
unsigned index = word->get_index();
vvp_darray*aobj = get_vvp_darray();
if(vp->format == vpiObjTypeVal) {
if(dynamic_cast<vvp_darray_real*>(aobj))
vp->format = vpiRealVal;
else if(dynamic_cast<vvp_darray_string*>(aobj))
vp->format = vpiStringVal;
else
vp->format = vpiVectorVal;
}
switch(vp->format) {
case vpiBinStrVal:
case vpiOctStrVal:
case vpiDecStrVal:
case vpiHexStrVal:
case vpiScalarVal:
case vpiIntVal:
{
vvp_vector4_t v;
aobj->get_word(index, v); // width == 1?
vpip_vec4_get_value(v, 1, false, vp); // TODO sign?
}
break;
case vpiVectorVal: // TODO vpip_vec2_ or vpip_vec4_?
{
vvp_vector4_t v;
aobj->get_word(index, v);
vpip_vec2_get_value(v, v.size(), false, vp); // TODO sign?
}
break;
case vpiRealVal:
{
double d;
aobj->get_word(index, d);
vpip_real_get_value(d, vp);
}
break;
case vpiStringVal:
{
string s;
aobj->get_word(index, s);
vpip_string_get_value(s, vp);
}
break;
default:
fprintf(stderr, "vpi sorry: format is not implemented\n");
assert(false);
}
}
void __vpiDarrayVar::put_word_value(struct __vpiArrayWord*word, p_vpi_value vp, int)
{
unsigned index = word->get_index();
vvp_darray*aobj = get_vvp_darray();
switch(vp->format) {
case vpiScalarVal:
{
vvp_vector4_t vec(1, vp->value.scalar);
aobj->set_word(index, vec);
}
break;
case vpiIntVal:
{
vvp_vector4_t vec;
vec.setarray(0, 8 * sizeof(vp->value.integer), (unsigned long*)(&vp->value.integer));
aobj->set_word(index, vec);
}
break;
case vpiVectorVal: // 2 vs 4 state logic?
{
int new_bit;
int size = get_word_size();
PLI_INT32 a = 0, b = 0;
vvp_vector4_t new_vec(size);
p_vpi_vecval vec = vp->value.vector;
vec--; // it will be increased in the first loop iteration
for(int i = 0; i < size; ++i) {
if(i % (8 * sizeof(vec->aval)) == 0) {
++vec;
a = vec->aval;
b = vec->bval;
}
// convert to vvp_bit4_t
new_bit = ((b & 1) << 2) | (a & 1);
new_vec.set_bit(i, (vvp_bit4_t) new_bit);
a >>= 1;
b >>= 1;
}
aobj->set_word(index, new_vec);
}
break;
case vpiRealVal:
aobj->set_word(index, vp->value.real);
break;
case vpiStringVal:
aobj->set_word(index, std::string(vp->value.str));
break;
default:
fprintf(stderr, "vpi sorry: format is not implemented");
assert(false);
}
}
vpiHandle __vpiDarrayVar::get_iter_index(struct __vpiArrayIterator*, int idx)
{
if (vals_words == 0) make_vals_words();
return &(vals_words[idx].as_word);
}
int __vpiDarrayVar::vpi_get(int code)
{
switch (code) {
case vpiArrayType:
return vpiDynamicArray;
case vpiSize:
if (aval == 0)
return 0;
else
return aval->get_size();
return get_size();
default:
return 0;
}
}
char* __vpiDarrayVar::vpi_get_str(int code)
{
if (code == vpiFile) { // Not implemented for now!
return simple_set_rbuf_str(file_names[0]);
}
return generic_get_str(code, scope_, name_, NULL);
}
vpiHandle __vpiDarrayVar::vpi_handle(int code)
{
switch (code) {
case vpiLeftRange:
return get_left_range();
case vpiRightRange:
return get_right_range();
case vpiScope:
return scope_;
case vpiModule:
return vpip_module(scope_);
}
return 0;
}
vpiHandle __vpiDarrayVar::vpi_index(int index)
{
if (index >= (long) get_size())
return 0;
if (index < 0)
return 0;
if (vals_words == 0)
make_vals_words();
return &(vals_words[index].as_word);
}
void __vpiDarrayVar::vpi_get_value(p_vpi_value val)
{
val->format = vpiSuppressVal;
}
vvp_darray*__vpiDarrayVar::get_vvp_darray() const
{
vvp_fun_signal_object*fun = dynamic_cast<vvp_fun_signal_object*> (get_net()->fun);
assert(fun);
vvp_object_t obj = fun->get_object();
return obj.peek<vvp_darray>();
}
vpiHandle vpip_make_darray_var(const char*name, vvp_net_t*net)
{
struct __vpiScope*scope = vpip_peek_current_scope();
const char*use_name = name ? vpip_name_string(name) : 0;
class __vpiDarrayVar*obj = new __vpiDarrayVar(scope, use_name, net);
__vpiDarrayVar*obj = new __vpiDarrayVar(scope, use_name, net);
return obj;
}

View File

@ -35,6 +35,10 @@
class class_type;
class vvp_darray;
class vvp_fun_arrayport;
typedef struct __vpiArray* vvp_array_t;
/*
* This header file contains the internal definitions that the vvp
@ -514,9 +518,11 @@ class __vpiBaseVar : public __vpiHandle {
inline vvp_net_t* get_net() const { return net_; }
private:
protected:
struct __vpiScope* scope_;
const char*name_;
private:
vvp_net_t*net_;
};
@ -532,14 +538,145 @@ class __vpiStringVar : public __vpiBaseVar {
extern vpiHandle vpip_make_string_var(const char*name, vvp_net_t*net);
class __vpiDarrayVar : public __vpiBaseVar {
struct __vpiArrayBase {
__vpiArrayBase() : vals_words(NULL) {}
virtual unsigned get_size(void) const = 0;
virtual vpiHandle get_left_range() = 0;
virtual vpiHandle get_right_range() = 0;
virtual struct __vpiScope*get_scope() const = 0;
virtual int get_word_size() const = 0;
virtual char*get_word_str(struct __vpiArrayWord*word, int code) = 0;
virtual void get_word_value(struct __vpiArrayWord*word, p_vpi_value vp) = 0;
virtual void put_word_value(struct __vpiArrayWord*word, p_vpi_value vp,
int flags) = 0;
virtual vpiHandle get_iter_index(struct __vpiArrayIterator*iter, int idx) = 0;
// vpi_iterate is already defined by vpiHandle, so to avoid problems with
// classes inheriting from vpiHandle and vpiArrayBase just share the common
// code in the following function
vpiHandle vpi_array_base_iterate(int code);
virtual void make_vals_words();
struct __vpiArrayWord*vals_words;
};
/*
* The vpiArray object holds an array of vpi objects that themselves
* represent the words of the array. The vpi_array_t is a pointer to
* a struct __vpiArray.
*
* The details of the implementation depends on what this is an array
* of. The easiest case is if this is an array of nets.
*
* - Array of Nets:
* If this represents an array of nets, then the nets member points to
* an array of vpiHandle objects. Each vpiHandle is a word. This is
* done because typically each word of a net array is simultaneously
* driven and accessed by other means, so there is no advantage to
* compacting the array in any other way.
*
* - Array of vector4 words.
* In this case, the nets pointer is nil, and the vals4 member points
* to a vvl_vector4array_t object that is a compact representation of
* an array of vvp_vector4_t vectors.
*
* - Array of real variables
* The vals member points to a dynamic array objects that has an
* array of double variables. This is very much like the way the
* vector4 array works.
*/
struct __vpiArray : public __vpiArrayBase, public __vpiHandle {
int get_type_code(void) const { return vpiMemory; }
unsigned get_size() const { return array_count; }
vpiHandle get_left_range() { assert(nets == 0); return &msb; }
vpiHandle get_right_range() { assert(nets == 0); return &lsb; }
struct __vpiScope*get_scope() const { return scope; }
int get_word_size() const;
char*get_word_str(struct __vpiArrayWord*word, int code);
void get_word_value(struct __vpiArrayWord*word, p_vpi_value vp);
void put_word_value(struct __vpiArrayWord*word, p_vpi_value vp, int flags);
vpiHandle get_iter_index(struct __vpiArrayIterator*iter, int idx);
int vpi_get(int code);
char* vpi_get_str(int code);
vpiHandle vpi_handle(int code);
inline vpiHandle vpi_iterate(int code) { return vpi_array_base_iterate(code); }
vpiHandle vpi_index(int idx);
void set_word(unsigned idx, unsigned off, vvp_vector4_t val);
void set_word(unsigned idx, double val);
void set_word(unsigned idx, const std::string&val);
void set_word(unsigned idx, const vvp_object_t&val);
vvp_vector4_t get_word(unsigned address);
double get_word_r(unsigned address);
void get_word_obj(unsigned address, vvp_object_t&val);
std::string get_word_str(unsigned address);
void alias_word(unsigned long addr, vpiHandle word, int msb, int lsb);
void attach_word(unsigned addr, vpiHandle word);
void word_change(unsigned long addr);
const char*name; /* Permanently allocated string */
__vpiDecConst first_addr;
__vpiDecConst last_addr;
__vpiDecConst msb;
__vpiDecConst lsb;
unsigned vals_width;
// If this is a net array, nets lists the handles.
vpiHandle*nets;
// If this is a var array, then these are used instead of nets.
vvp_vector4array_t*vals4;
vvp_darray *vals;
vvp_fun_arrayport*ports_;
struct __vpiCallback *vpi_callbacks;
bool signed_flag;
bool swap_addr;
private:
unsigned array_count;
struct __vpiScope*scope;
friend vpiHandle vpip_make_array(char*label, const char*name,
int first_addr, int last_addr,
bool signed_flag);
friend void compile_array_alias(char*label, char*name, char*src);
};
class __vpiDarrayVar : public __vpiBaseVar, public __vpiArrayBase {
public:
__vpiDarrayVar(__vpiScope*scope, const char*name, vvp_net_t*net);
int get_type_code(void) const;
int get_type_code() const { return vpiArrayVar; }
unsigned get_size() const;
vpiHandle get_left_range();
vpiHandle get_right_range();
struct __vpiScope*get_scope() const { return scope_; }
int get_word_size() const;
char*get_word_str(struct __vpiArrayWord*word, int code);
void get_word_value(struct __vpiArrayWord*word, p_vpi_value vp);
void put_word_value(struct __vpiArrayWord*word, p_vpi_value vp, int flags);
vpiHandle get_iter_index(struct __vpiArrayIterator*iter, int idx);
inline vpiHandle vpi_iterate(int code) { return vpi_array_base_iterate(code); }
int vpi_get(int code);
char* vpi_get_str(int code);
vpiHandle vpi_handle(int code);
vpiHandle vpi_index(int index);
void vpi_get_value(p_vpi_value val);
protected:
vvp_darray*get_vvp_darray() const;
__vpiDecConst left_range_, right_range_;
};
extern vpiHandle vpip_make_darray_var(const char*name, vvp_net_t*net);

View File

@ -654,7 +654,7 @@ static vpiHandle signal_iterate(int code, vpiHandle ref)
assert(rfp);
if (code == vpiIndex) {
return rfp->is_netarray? array_index_iterate(code, rfp->id.index) : 0;
return rfp->is_netarray ? rfp->id.index->vpi_iterate(code) : 0;
}
return 0;

View File

@ -1020,7 +1020,7 @@ bool of_ASSIGN_AV(vthread_t thr, vvp_code_t cp)
if (adr < 0) return true;
long vwidth = get_array_word_size(cp->array);
long vwidth = cp->array->get_word_size();
// We fell off the MSB end.
if (off >= vwidth) return true;
// Trim the bits after the MSB
@ -1059,7 +1059,7 @@ bool of_ASSIGN_AVD(vthread_t thr, vvp_code_t cp)
if (adr < 0) return true;
long vwidth = get_array_word_size(cp->array);
long vwidth = cp->array->get_word_size();
// We fell off the MSB end.
if (off >= vwidth) return true;
// Trim the bits after the MSB
@ -1091,7 +1091,7 @@ bool of_ASSIGN_AVE(vthread_t thr, vvp_code_t cp)
if (adr < 0) return true;
long vwidth = get_array_word_size(cp->array);
long vwidth = cp->array->get_word_size();
// We fell off the MSB end.
if (off >= vwidth) return true;
// Trim the bits after the MSB
@ -3262,7 +3262,7 @@ bool of_LOAD_AR(vthread_t thr, vvp_code_t cp)
if (thr_get_bit(thr, 4) == BIT4_1) {
word = 0.0;
} else {
word = array_get_word_r(cp->array, adr);
word = cp->array->get_word_r(adr);
}
thr->push_real(word);
@ -3294,7 +3294,7 @@ bool of_LOAD_AV(vthread_t thr, vvp_code_t cp)
return true;
}
vvp_vector4_t word = array_get_word(cp->array, adr);
vvp_vector4_t word = cp->array->get_word(adr);
if (word.size() > wid)
word.resize(wid);
@ -3451,7 +3451,7 @@ bool of_LOAD_AVP0(vthread_t thr, vvp_code_t cp)
/* We need a vector this wide to make the math work correctly.
* Copy the base bits into the vector, but keep the width. */
vvp_vector4_t sig_value(wid, BIT4_0);
sig_value.copy_bits(array_get_word(cp->array, adr));
sig_value.copy_bits(cp->array->get_word(adr));
load_vp0_common(thr, cp, sig_value);
return true;
@ -3471,7 +3471,7 @@ bool of_LOAD_AVP0_S(vthread_t thr, vvp_code_t cp)
return true;
}
vvp_vector4_t tmp (array_get_word(cp->array, adr));
vvp_vector4_t tmp (cp->array->get_word(adr));
/* We need a vector this wide to make the math work correctly.
* Copy the base bits into the vector, but keep the width. */
@ -3505,7 +3505,7 @@ bool of_LOAD_AVX_P(vthread_t thr, vvp_code_t cp)
long use_index = thr->words[index].w_int;
vvp_vector4_t word = array_get_word(cp->array, adr);
vvp_vector4_t word = cp->array->get_word(adr);
if ((use_index >= (long)word.size()) || (use_index < 0)) {
thr_put_bit(thr, bit, BIT4_X);
@ -3543,7 +3543,7 @@ bool of_LOAD_OBJA(vthread_t thr, vvp_code_t cp)
if (thr_get_bit(thr, 4) == BIT4_1) {
; // Return nil
} else {
array_get_word_obj(cp->array, adr, word);
cp->array->get_word_obj(adr, word);
}
thr->push_object(word);
@ -3591,7 +3591,7 @@ bool of_LOAD_STRA(vthread_t thr, vvp_code_t cp)
if (thr_get_bit(thr, 4) == BIT4_1) {
word = "";
} else {
word = array_get_word_str(cp->array, adr);
word = cp->array->get_word_str(adr);
}
thr->push_str(word);
@ -5051,7 +5051,7 @@ bool of_SET_AV(vthread_t thr, vvp_code_t cp)
/* Make a vector of the desired width. */
vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid);
array_set_word(cp->array, adr, off, value);
cp->array->set_word(adr, off, value);
return true;
}
@ -5482,7 +5482,7 @@ bool of_STORE_OBJA(vthread_t thr, vvp_code_t cp)
vvp_object_t val;
thr->pop_object(val);
array_set_word(cp->array, adr, val);
cp->array->set_word(adr, val);
return true;
}
@ -5653,7 +5653,7 @@ bool of_STORE_REALA(vthread_t thr, vvp_code_t cp)
unsigned adr = thr->words[idx].w_int;
double val = thr->pop_real();
array_set_word(cp->array, adr, val);
cp->array->set_word(adr, val);
return true;
}
@ -5678,7 +5678,7 @@ bool of_STORE_STRA(vthread_t thr, vvp_code_t cp)
unsigned adr = thr->words[idx].w_int;
string val = thr->pop_str();
array_set_word(cp->array, adr, val);
cp->array->set_word(adr, val);
return true;
}
@ -5861,7 +5861,7 @@ bool of_TEST_NUL_A(vthread_t thr, vvp_code_t cp)
return true;
}
array_get_word_obj(cp->array, adr, word);
cp->array->get_word_obj(adr, word);
if (word.test_nil())
thr_put_bit(thr, 4, BIT4_1);
else

View File

@ -59,7 +59,7 @@ static void __compile_var_real(char*label, char*name,
}
if (array) {
assert(!name);
array_attach_word(array, array_addr, obj);
array->attach_word(array_addr, obj);
}
free(label);
delete[] name;
@ -365,7 +365,7 @@ static void do_compile_net(vvp_net_t*node, vvp_array_t array,
define_functor_symbol(my_label, node);
if (array)
array_attach_word(array, array_addr, obj);
array->attach_word(array_addr, obj);
else if (obj)
vpip_attach_to_scope(scope,obj);
@ -495,7 +495,7 @@ static void __compile_real_net2(vvp_net_t*node, vvp_array_t array,
define_functor_symbol(my_label, node);
if (array)
array_attach_word(array, array_addr, obj);
array->attach_word(array_addr, obj);
else if (obj)
vpip_attach_to_scope(scope, obj);
@ -583,7 +583,7 @@ void compile_aliasw(char*label, char*array_label, unsigned long array_addr,
vpiHandle obj = vvp_lookup_handle(argv[0].text);
assert(obj);
array_alias_word(array, array_addr, obj, msb, lsb);
array->alias_word(array_addr, obj, msb, lsb);
free(label);
free(array_label);