Merge branch 'master' of github.com:steveicarus/iverilog
This commit is contained in:
commit
9e10645722
1
PWire.cc
1
PWire.cc
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
55
elab_sig.cc
55
elab_sig.cc
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
13
elaborate.cc
13
elaborate.cc
|
|
@ -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,
|
||||
|
|
|
|||
116
netmisc.cc
116
netmisc.cc
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
29
parse.y
|
|
@ -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
|
||||
|
|
|
|||
6
pform.cc
6
pform.cc
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
302
vpi/sys_darray.c
302
vpi/sys_darray.c
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue