Merge branch 'master' of github.com:steveicarus/iverilog

This commit is contained in:
Stephen Williams 2019-09-17 14:12:43 -07:00
commit 9e10645722
13 changed files with 154 additions and 524 deletions

View File

@ -67,6 +67,7 @@ bool PWire::set_wire_type(NetNet::Type t)
isint_ = true;
return true;
}
if (t == NetNet::IMPLICIT_REG) return true;
return false;
case NetNet::REG:
if (t == NetNet::INTEGER) {

View File

@ -5397,12 +5397,11 @@ NetExpr* PENewArray::elaborate_expr(Design*des, NetScope*scope,
return tmp;
}
/*
* This method should never actually be called.
*/
NetExpr* PENewArray::elaborate_expr(Design*, NetScope*, unsigned, unsigned) const
NetExpr* PENewArray::elaborate_expr(Design*des, NetScope*, unsigned, unsigned) const
{
ivl_assert(*this, 0);
cerr << get_fileline() << ": error: The new array constructor may "
"only be used in an assignment to a dynamic array." << endl;
des->errors += 1;
return 0;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-2019 Stephen Williams (steve@icarus.com)
* Copyright CERN 2012 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
@ -47,6 +47,8 @@
using namespace std;
#if 0
/* These functions are not currently used. */
static bool get_const_argument(NetExpr*exp, verinum&res)
{
switch (exp->expr_type()) {
@ -73,8 +75,6 @@ static bool get_const_argument(NetExpr*exp, verinum&res)
return true;
}
#if 0
/* This function is not currently used. */
static bool get_const_argument(NetExpr*exp, long&res)
{
verinum tmp;
@ -876,13 +876,13 @@ static ivl_type_s*elaborate_type(Design*des, NetScope*scope,
return 0;
}
static netparray_t* elaborate_parray_type(Design*des, NetScope*scope,
static netparray_t* elaborate_parray_type(Design*des, NetScope*scope, const LineInfo*li,
parray_type_t*data_type)
{
vector<netrange_t>packed_dimensions;
bool bad_range = evaluate_ranges(des, scope, packed_dimensions, * data_type->dims);
ivl_assert(*data_type, !bad_range);
bool dimensions_ok = evaluate_ranges(des, scope, li, packed_dimensions, * data_type->dims);
ivl_assert(*data_type, dimensions_ok);
ivl_type_s*element_type = elaborate_type(des, scope, data_type->base_type);
@ -998,7 +998,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
<< " inherits dimensions from var/net." << endl;
}
bool bad_range = false;
bool dimensions_ok = true;
vector<netrange_t> plist, nlist;
/* If they exist get the port definition MSB and LSB */
if (port_set_ && !port_.empty()) {
@ -1006,7 +1006,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
cerr << get_fileline() << ": PWire::elaborate_sig: "
<< "Evaluate ranges for port " << basename() << endl;
}
bad_range |= evaluate_ranges(des, scope, plist, port_);
dimensions_ok &= evaluate_ranges(des, scope, this, plist, port_);
nlist = plist;
/* An implicit port can have a range so note that here. */
is_implicit_scalar = false;
@ -1014,13 +1014,13 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
assert(port_set_ || port_.empty());
/* If they exist get the net/etc. definition MSB and LSB */
if (net_set_ && !net_.empty() && !bad_range) {
if (net_set_ && !net_.empty() && dimensions_ok) {
nlist.clear();
if (debug_elaborate) {
cerr << get_fileline() << ": PWire::elaborate_sig: "
<< "Evaluate ranges for net " << basename() << endl;
}
bad_range |= evaluate_ranges(des, scope, nlist, net_);
dimensions_ok &= evaluate_ranges(des, scope, this, nlist, net_);
}
assert(net_set_ || net_.empty());
@ -1121,39 +1121,10 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
// Cannot handle dynamic arrays of arrays yet.
ivl_assert(*this, netdarray==0);
ivl_assert(*this, use_lidx && use_ridx);
NetExpr*lexp = elab_and_eval(des, scope, use_lidx, -1, true);
NetExpr*rexp = elab_and_eval(des, scope, use_ridx, -1, true);
if ((lexp == 0) || (rexp == 0)) {
cerr << get_fileline() << ": internal error: There is "
<< "a problem evaluating indices for ``"
<< name_ << "''." << endl;
des->errors += 1;
return 0;
}
bool const_flag = true;
verinum lval, rval;
const_flag &= get_const_argument(lexp, lval);
const_flag &= get_const_argument(rexp, rval);
delete rexp;
delete lexp;
long index_l, index_r;
if (! const_flag) {
cerr << get_fileline() << ": error: The indices "
<< "are not constant for array ``"
<< name_ << "''." << endl;
des->errors += 1;
/* Attempt to recover from error, */
index_l = 0;
index_r = 0;
} else {
index_l = lval.as_long();
index_r = rval.as_long();
}
evaluate_range(des, scope, this, *cur, index_l, index_r);
if (abs(index_r - index_l) > warn_dimension_size) {
cerr << get_fileline() << ": warning: Array dimension "
"is greater than " << warn_dimension_size
@ -1276,7 +1247,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
// The trick here is that the parray type has an
// arbitrary sub-type, and not just a scalar bit...
netparray_t*use_type = elaborate_parray_type(des, scope, parray_type);
netparray_t*use_type = elaborate_parray_type(des, scope, this, parray_type);
// Should not be getting packed dimensions other than
// through the parray type declaration.
ivl_assert(*this, packed_dimensions.empty());

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2017 Stephen Williams (steve@icarus.com)
* Copyright (c) 2012-2019 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
@ -257,9 +257,9 @@ ivl_type_s* uarray_type_t::elaborate_type_raw(Design*des, NetScope*scope) const
}
vector<netrange_t> dimensions;
bool bad_range = evaluate_ranges(des, scope, dimensions, *dims);
bool dimensions_ok = evaluate_ranges(des, scope, this, dimensions, *dims);
if (bad_range) {
if (!dimensions_ok) {
cerr << get_fileline() << " : warning: "
<< "Bad dimensions for type here." << endl;
}

View File

@ -2318,8 +2318,17 @@ NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
NetExpr*rv = rval_->elaborate_expr(des, scope, net_type, 0);
ivl_assert(*this, !is_constant_);
return rv;
if (!is_constant_ || !rv) return rv;
if (dynamic_cast<NetENew*>(rv)) return rv;
cerr << get_fileline() << ": error: "
"The RHS expression must be constant." << endl;
cerr << get_fileline() << " : "
"This expression violates the rule: " << *rv << endl;
des->errors += 1;
delete rv;
return 0;
}
NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,

View File

@ -1052,50 +1052,94 @@ NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name,
return tmp;
}
bool evaluate_ranges(Design*des, NetScope*scope,
bool evaluate_range(Design*des, NetScope*scope, const LineInfo*li,
const pform_range_t&range, long&index_l, long&index_r)
{
bool dimension_ok = true;
// Unsized and queue dimensions should be handled before calling
// this function. If we find them here, we are in a context where
// they are not allowed.
if (range.first == 0) {
cerr << li->get_fileline() << ": error: "
"An unsized dimension is not allowed here." << endl;
dimension_ok = false;
des->errors += 1;
} else if (dynamic_cast<PENull*>(range.first)) {
cerr << li->get_fileline() << ": error: "
"A queue dimension is not allowed here." << endl;
dimension_ok = false;
des->errors += 1;
} else {
NetExpr*texpr = elab_and_eval(des, scope, range.first, -1, true);
if (! eval_as_long(index_l, texpr)) {
cerr << range.first->get_fileline() << ": error: "
"Dimensions must be constant." << endl;
cerr << range.first->get_fileline() << " : "
<< (range.second ? "This MSB" : "This size")
<< " expression violates the rule: "
<< *range.first << endl;
dimension_ok = false;
des->errors += 1;
}
delete texpr;
if (range.second == 0) {
// This is a SystemVerilog [size] dimension. The IEEE
// standard does not allow this in a packed dimension,
// but we do. At least one commercial simulator does too.
if (!dimension_ok) {
// bail out
} else if (index_l > 0) {
index_l = index_l - 1;
index_r = 0;
} else {
cerr << range.first->get_fileline() << ": error: "
"Dimension size must be greater than zero." << endl;
cerr << range.first->get_fileline() << " : "
"This size expression violates the rule: "
<< *range.first << endl;
dimension_ok = false;
des->errors += 1;
}
} else {
texpr = elab_and_eval(des, scope, range.second, -1, true);
if (! eval_as_long(index_r, texpr)) {
cerr << range.second->get_fileline() << ": error: "
"Dimensions must be constant." << endl;
cerr << range.second->get_fileline() << " : "
"This LSB expression violates the rule: "
<< *range.second << endl;
dimension_ok = false;
des->errors += 1;
}
delete texpr;
}
}
/* Error recovery */
if (!dimension_ok) {
index_l = 0;
index_r = 0;
}
return dimension_ok;
}
bool evaluate_ranges(Design*des, NetScope*scope, const LineInfo*li,
vector<netrange_t>&llist,
const list<pform_range_t>&rlist)
{
bool bad_msb = false, bad_lsb = false;
bool dimensions_ok = true;
for (list<pform_range_t>::const_iterator cur = rlist.begin()
; cur != rlist.end() ; ++cur) {
long use_msb, use_lsb;
NetExpr*texpr = elab_and_eval(des, scope, cur->first, -1, true);
if (! eval_as_long(use_msb, texpr)) {
cerr << cur->first->get_fileline() << ": error: "
"Range expressions must be constant." << endl;
cerr << cur->first->get_fileline() << " : "
"This MSB expression violates the rule: "
<< *cur->first << endl;
des->errors += 1;
bad_msb = true;
}
delete texpr;
texpr = elab_and_eval(des, scope, cur->second, -1, true);
if (! eval_as_long(use_lsb, texpr)) {
cerr << cur->second->get_fileline() << ": error: "
"Range expressions must be constant." << endl;
cerr << cur->second->get_fileline() << " : "
"This LSB expression violates the rule: "
<< *cur->second << endl;
des->errors += 1;
bad_lsb = true;
}
delete texpr;
/* Error recovery */
if (bad_lsb) use_lsb = 0;
if (bad_msb) use_msb = use_lsb;
llist.push_back(netrange_t(use_msb, use_lsb));
long index_l, index_r;
dimensions_ok &= evaluate_range(des, scope, li, *cur, index_l, index_r);
llist.push_back(netrange_t(index_l, index_r));
}
return bad_msb | bad_lsb;
return dimensions_ok;
}
void eval_expr(NetExpr*&expr, int context_width)

View File

@ -1,7 +1,7 @@
#ifndef IVL_netmisc_H
#define IVL_netmisc_H
/*
* Copyright (c) 1999-2017 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2019 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
@ -321,7 +321,11 @@ extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
bool need_const =false,
bool force_unsigned =false);
extern bool evaluate_ranges(Design*des, NetScope*scope,
extern bool evaluate_range(Design*des, NetScope*scope, const LineInfo*li,
const pform_range_t&range,
long&index_l, long&index_r);
extern bool evaluate_ranges(Design*des, NetScope*scope, const LineInfo*li,
std::vector<netrange_t>&llist,
const std::list<pform_range_t>&rlist);
/*

29
parse.y
View File

@ -1,7 +1,7 @@
%{
/*
* Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2019 Stephen Williams (steve@icarus.com)
* Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
@ -1563,6 +1563,15 @@ variable_decl_assignment /* IEEE1800-2005 A.2.3 */
delete[]$1;
$$ = tmp;
}
| IDENTIFIER dimensions '=' dynamic_array_new
{ decl_assignment_t*tmp = new decl_assignment_t;
tmp->name = lex_strings.make($1);
tmp->index = *$2;
tmp->expr .reset($4);
delete $2;
delete[]$1;
$$ = tmp;
}
;
@ -2346,9 +2355,7 @@ variable_dimension /* IEEE1800-2005: A.2.5 */
<< "Use at least -g2005-sv to remove this warning." << endl;
}
list<pform_range_t> *tmp = new list<pform_range_t>;
pform_range_t index;
index.first = new PENumber(new verinum((uint64_t)0, integer_width));
index.second = new PEBinary('-', $2, new PENumber(new verinum((uint64_t)1, integer_width)));
pform_range_t index ($2,0);
tmp->push_back(index);
$$ = tmp;
}
@ -5694,6 +5701,20 @@ register_variable
pform_make_var_init(@1, name, $4);
$$ = $1;
}
| IDENTIFIER dimensions_opt '=' dynamic_array_new
{ if (pform_peek_scope()->var_init_needs_explicit_lifetime()
&& (var_lifetime == LexicalScope::INHERITED)) {
cerr << @3 << ": warning: Static variable initialization requires "
"explicit lifetime in this context." << endl;
warn_count += 1;
}
perm_string name = lex_strings.make($1);
pform_makewire(@1, name, NetNet::REG,
NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0);
pform_set_reg_idx(name, $2);
pform_make_var_init(@1, name, $4);
$$ = $1;
}
;
register_variable_list

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2019 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
@ -2710,6 +2710,8 @@ void pform_makewire(const struct vlltype&li,
for (list<decl_assignment_t*>::iterator cur = assign_list->begin()
; cur != assign_list->end() ; ++ cur) {
decl_assignment_t* curp = *cur;
pform_makewire(li, curp->name, type, NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0);
pform_set_reg_idx(curp->name, &curp->index);
names->push_back(curp->name);
}
@ -2722,8 +2724,6 @@ void pform_makewire(const struct vlltype&li,
if (type == NetNet::REG || type == NetNet::IMPLICIT_REG) {
pform_make_var_init(li, first->name, expr);
} else {
PWire*cur = pform_get_wire_in_scope(first->name);
assert(cur);
PEIdent*lval = new PEIdent(first->name);
FILE_NAME(lval, li.text, li.first_line);
PGAssign*ass = pform_make_pgassign(lval, expr, delay, str);

View File

@ -154,6 +154,12 @@ void pform_package_import(const struct vlltype&, PPackage*pkg, const char*ident)
scope->imports[cur->first] = pkg;
}
for (map<perm_string,PWire*>::const_iterator cur = pkg->wires.begin()
; cur != pkg->wires.end() ; ++cur) {
scope->imports[cur->first] = pkg;
}
for (set<enum_type_t*>::const_iterator cur = pkg->enum_sets.begin()
; cur != pkg->enum_sets.end() ; ++ cur) {
scope->enum_sets.insert(*cur);

View File

@ -1020,6 +1020,7 @@ static int show_stmt_assign_sig_darray(ivl_statement_t net)
} else if (mux) {
draw_eval_vec4(rval);
resize_vec4_wid(rval, ivl_stmt_lwidth(net));
/* The %store/dar/vec4 expects the array index to be in index
register 3. Calculate the index in place. */

View File

@ -97,287 +97,6 @@ static PLI_INT32 dobject_size_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
return 0;
}
static PLI_INT32 to_from_vec_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv, arg;
argv = vpi_iterate(vpiArgument, callh);
if (argv == 0) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s requires two arguments.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
/* The first argument must be a dynamic array. */
arg = vpi_scan(argv); /* This should never be zero. */
assert(arg);
if (vpi_get(vpiType, arg) != vpiArrayVar) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s first argument must be a dynamic array, "
"given a %s.\n", name, vpi_get_str(vpiType, arg));
vpi_control(vpiFinish, 1);
}
if (vpi_get(vpiArrayType, arg) != vpiDynamicArray) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s first argument must be a dynamic array.\n", name);
vpi_control(vpiFinish, 1);
}
// HERE: Still need to verify that this is not a real or string array.
// That will require adding TypeSpec support to the VPI.
/* The second argument must be a net, reg or bit variable. */
arg = vpi_scan(argv);
if (arg == 0) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s requires a second argument.\n", name);
vpi_control(vpiFinish, 1);
}
switch(vpi_get(vpiType, arg)) {
case vpiNet:
case vpiReg:
case vpiBitVar:
case vpiIntegerVar:
case vpiConstant:
break;
default:
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s second argument must be a logical net or "
"variable.\n", name);
vpi_control(vpiFinish, 1);
}
arg = vpi_scan(argv);
if (arg != 0) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s has too many arguments.\n", name);
vpi_control(vpiFinish, 1);
vpi_free_object(argv);
}
return 0;
}
static const size_t BPW = 8 * sizeof(PLI_INT32);
static const size_t BPWM1 = 8 * sizeof(PLI_INT32) - 1;
static PLI_INT32 to_vec_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle darr = vpi_scan(argv);
vpiHandle vec = vpi_scan(argv);
vpi_free_object(argv);
/* Calculate and check the basic array and vector information. */
int darr_size = vpi_get(vpiSize, darr);
int darr_word_size = vpi_get(vpiSize, vpi_handle_by_index(darr, 0));
assert(darr_word_size > 0);
int darr_bit_size = darr_size * darr_word_size;
int vec_size = vpi_get(vpiSize, vec);
if (darr_size <= 0) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s cannot cast an empty dynamic array.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
if (darr_bit_size != vec_size) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s dynamic array and vector size do not match "
"(%d != %d).\n", name, darr_bit_size, vec_size);
vpi_control(vpiFinish, 1);
return 0;
}
/* Calculate the number of words needed to hold the dynamic array
* bits and allocate enough space for them. */
size_t vec_words = (darr_bit_size + BPWM1) / BPW;
s_vpi_vecval *vec_val = calloc(vec_words, sizeof(s_vpi_vecval));
s_vpi_vecval *vec_ptr = vec_val;
/* The number of words in each array element. */
unsigned darr_words = (darr_word_size + BPWM1) / BPW;
/* The offset in bits into the current vector value. */
unsigned offset = 0;
/* We want to get each array word as a vector. */
s_vpi_value darr_val;
darr_val.format = vpiVectorVal;
/* We have to reverse the order of the dynamic array words. */
for (PLI_INT32 i = darr_size - 1; i >= 0; --i) {
/* Get the vector value for the current array word. */
vpiHandle darr_word = vpi_handle_by_index(darr, i);
vpi_get_value(darr_word, &darr_val);
assert(darr_val.format == vpiVectorVal);
/* The number of bits to copy for this array word. */
unsigned bits_to_copy = (unsigned)darr_word_size;
/* Copy the current array bits to the vector and update the
* the vector pointer accordingly. */
for (unsigned j = 0; j < darr_words; ++j) {
/* Get the current array part and copy it into the
* correct place. */
PLI_UINT32 aval = darr_val.value.vector->aval;
PLI_UINT32 bval = darr_val.value.vector->bval;
assert(offset < BPW);
vec_ptr->aval |= (aval << offset);
vec_ptr->bval |= (bval << offset);
/* Calculate the new offset into the vector. */
offset += (bits_to_copy > BPW) ? BPW : bits_to_copy;
/* If the new offset is past the end of the vector part
* then the next vector part also needs to be used. */
if (offset >= BPW) {
++vec_ptr;
/* Does the current array part also go into the
* next vector part? */
if (offset > BPW) {
/* This code has not been tested since the
* current implementation only supports dynamic
* array elements of size 8, 16, 32 or 64 bits
* so currently this code is never run. For
* now assert since it has not been checked. */
assert(0);
/* Copy the rest of the array part that did not
* fit in the previous vector part to the next
* vector part. */
offset -= BPW;
vec_ptr->aval |= (aval >> (darr_word_size -
offset));
vec_ptr->bval |= (bval >> (darr_word_size -
offset));
/* Start at the beginning of the next vector part. */
} else {
offset = 0;
}
}
/* Advance to the next part of the array. */
bits_to_copy -= BPW;
darr_val.value.vector++;
}
}
/* Put the result to the vector and free the allocated space. */
darr_val.format = vpiVectorVal;
darr_val.value.vector = vec_val;
vpi_put_value(vec, &darr_val, 0, vpiNoDelay);
free(vec_val);
return 0;
}
static PLI_INT32 from_vec_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle darr = vpi_scan(argv);
vpiHandle vec = vpi_scan(argv);
vpi_free_object(argv);
/* Calculate and check the basic array and vector information. */
int darr_size = vpi_get(vpiSize, darr);
int darr_word_size = vpi_get(vpiSize, vpi_handle_by_index(darr, 0));
assert(darr_word_size > 0);
int darr_bit_size = darr_size * darr_word_size;
int vec_size = vpi_get(vpiSize, vec);
if (vec_size <= 0) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s cannot cast an empty vector array.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
if (darr_bit_size != vec_size) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s dynamic array and vector size do not match "
"(%d != %d).\n", name, darr_bit_size, vec_size);
vpi_control(vpiFinish, 1);
return 0;
}
/* Calculate the number of words needed to hold the dynamic array
* word bits and allocate enough space for them. */
size_t darr_words = (darr_word_size + BPWM1) / BPW;
s_vpi_vecval *darr_val = calloc(darr_words, sizeof(s_vpi_vecval));
/* Get the vector value. */
s_vpi_value vec_val;
vec_val.format = vpiVectorVal;
vpi_get_value(vec, &vec_val);
/* The offset in bits into the vector value. */
unsigned offset = 0;
/* We have to reverse the order of the dynamic array words. */
for (int i = darr_size - 1; i >= 0; --i) {
unsigned bits_to_copy = darr_word_size;
s_vpi_vecval *darr_ptr = darr_val;
/* Copy some of the vector bits to the current array word. */
while (bits_to_copy > 0) {
unsigned copied_bits = (bits_to_copy > BPW) ? BPW :
bits_to_copy;
/* Start with the current vector part. */
PLI_UINT32 aval = vec_val.value.vector[offset / BPW].aval;
PLI_UINT32 bval = vec_val.value.vector[offset / BPW].bval;
/* If this isn't aligned then we may need to get bits
* from the next part as well. */
unsigned rem_bits = offset % BPW;
if (rem_bits) {
aval >>= rem_bits;
aval |= vec_val.value.vector[offset / BPW + 1].aval <<
(BPW - rem_bits);
bval >>= rem_bits;
bval |= vec_val.value.vector[offset / BPW + 1].bval <<
(BPW - rem_bits);
}
/* Advance to the next part of the array and vector. */
darr_ptr->aval = aval;
darr_ptr->bval = bval;
darr_ptr++;
offset += copied_bits;
bits_to_copy -= copied_bits;
}
/* Put part of the vector to the current dynamic array word. */
s_vpi_value result;
result.format = vpiVectorVal;
result.value.vector = darr_val;
vpiHandle darr_word = vpi_handle_by_index(darr, i);
vpi_put_value(darr_word, &result, 0, vpiNoDelay);
}
free(darr_val);
return 0;
}
void sys_darray_register(void)
{
s_vpi_systf_data tf_data;
@ -392,25 +111,4 @@ void sys_darray_register(void)
tf_data.user_data = "$size";
res = vpi_register_systf(&tf_data);
vpip_make_systf_system_defined(res);
tf_data.type = vpiSysTask;
tf_data.sysfunctype = 0;
tf_data.tfname = "$ivl_darray_method$to_vec";
tf_data.calltf = to_vec_calltf;
tf_data.compiletf = to_from_vec_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$ivl_darray_method$to_vec";
res = vpi_register_systf(&tf_data);
vpip_make_systf_system_defined(res);
tf_data.type = vpiSysTask;
tf_data.sysfunctype = 0;
tf_data.tfname = "$ivl_darray_method$from_vec";
tf_data.calltf = from_vec_calltf;
tf_data.compiletf = to_from_vec_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$ivl_darray_method$from_vec";
res = vpi_register_systf(&tf_data);
vpip_make_systf_system_defined(res);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 2012-2019 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
@ -78,120 +78,6 @@ 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;
@ -206,14 +92,4 @@ 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);
}