Merge pull request #49 from orsonmmz/darray_vpi
Support for dynamic arrays in the VPI
This commit is contained in:
commit
f3ba335493
9
PExpr.cc
9
PExpr.cc
|
|
@ -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
22
PExpr.h
|
|
@ -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.
|
||||
|
|
|
|||
94
elab_expr.cc
94
elab_expr.cc
|
|
@ -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
12
parse.y
|
|
@ -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
|
||||
|
|
|
|||
2
pform.cc
2
pform.cc
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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_) {
|
||||
|
|
|
|||
11
sys_funcs.cc
11
sys_funcs.cc
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
1122
vvp/array.cc
1122
vvp/array.cc
File diff suppressed because it is too large
Load Diff
23
vvp/array.h
23
vvp/array.h
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
143
vvp/vpi_priv.h
143
vvp/vpi_priv.h
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue