Merge branch 'master' of ssh://steve-icarus@icarus.com/home/u/icarus/steve/git/verilog
This commit is contained in:
commit
afa2478801
17
PExpr.h
17
PExpr.h
|
|
@ -306,6 +306,11 @@ class PEIdent : public PExpr {
|
||||||
private:
|
private:
|
||||||
// Common functions to calculate parts of part/bit selects.
|
// Common functions to calculate parts of part/bit selects.
|
||||||
bool calculate_parts_(Design*, NetScope*, long&msb, long&lsb) const;
|
bool calculate_parts_(Design*, NetScope*, long&msb, long&lsb) const;
|
||||||
|
NetExpr* calculate_up_do_base_(Design*, NetScope*) const;
|
||||||
|
bool calculate_param_range_(Design*, NetScope*,
|
||||||
|
const NetExpr*msb_ex, long&msb,
|
||||||
|
const NetExpr*lsb_ex, long&lsb) const;
|
||||||
|
|
||||||
bool calculate_up_do_width_(Design*, NetScope*, unsigned long&wid) const;
|
bool calculate_up_do_width_(Design*, NetScope*, unsigned long&wid) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -321,6 +326,18 @@ class PEIdent : public PExpr {
|
||||||
NetScope*found,
|
NetScope*found,
|
||||||
const NetExpr*par_msb,
|
const NetExpr*par_msb,
|
||||||
const NetExpr*par_lsb) const;
|
const NetExpr*par_lsb) const;
|
||||||
|
NetExpr*elaborate_expr_param_part_(Design*des,
|
||||||
|
NetScope*scope,
|
||||||
|
const NetExpr*par,
|
||||||
|
NetScope*found,
|
||||||
|
const NetExpr*par_msb,
|
||||||
|
const NetExpr*par_lsb) const;
|
||||||
|
NetExpr*elaborate_expr_param_idx_up_(Design*des,
|
||||||
|
NetScope*scope,
|
||||||
|
const NetExpr*par,
|
||||||
|
NetScope*found,
|
||||||
|
const NetExpr*par_msb,
|
||||||
|
const NetExpr*par_lsb) const;
|
||||||
NetExpr*elaborate_expr_net(Design*des,
|
NetExpr*elaborate_expr_net(Design*des,
|
||||||
NetScope*scope,
|
NetScope*scope,
|
||||||
NetNet*net,
|
NetNet*net,
|
||||||
|
|
|
||||||
355
elab_expr.cc
355
elab_expr.cc
|
|
@ -882,6 +882,51 @@ bool PEIdent::calculate_up_do_width_(Design*des, NetScope*scope,
|
||||||
return flag;
|
return flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When we know that this is an indexed part select (up or down) this
|
||||||
|
* method calculates the up/down base, as far at it can be calculated.
|
||||||
|
*/
|
||||||
|
NetExpr* PEIdent::calculate_up_do_base_(Design*des, NetScope*scope) const
|
||||||
|
{
|
||||||
|
const name_component_t&name_tail = path_.back();
|
||||||
|
ivl_assert(*this, !name_tail.index.empty());
|
||||||
|
|
||||||
|
const index_component_t&index_tail = name_tail.index.back();
|
||||||
|
ivl_assert(*this, index_tail.lsb != 0);
|
||||||
|
ivl_assert(*this, index_tail.msb != 0);
|
||||||
|
|
||||||
|
NetExpr*tmp = elab_and_eval(des, scope, index_tail.msb, -1);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PEIdent::calculate_param_range_(Design*des, NetScope*scope,
|
||||||
|
const NetExpr*par_msb, long&par_msv,
|
||||||
|
const NetExpr*par_lsb, long&par_lsv) const
|
||||||
|
{
|
||||||
|
if (par_msb == 0) {
|
||||||
|
// If the parameter doesn't have an explicit range, then
|
||||||
|
// just return range values of 0:0. The par_msv==0 is
|
||||||
|
// correct. The par_msv is not necessarily correct, but
|
||||||
|
// clients of this function don't need a correct value.
|
||||||
|
ivl_assert(*this, par_lsb == 0);
|
||||||
|
par_msv = 0;
|
||||||
|
par_lsv = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NetEConst*tmp = dynamic_cast<const NetEConst*> (par_msb);
|
||||||
|
ivl_assert(*this, tmp);
|
||||||
|
|
||||||
|
par_msv = tmp->value().as_long();
|
||||||
|
|
||||||
|
tmp = dynamic_cast<const NetEConst*> (par_lsb);
|
||||||
|
ivl_assert(*this, tmp);
|
||||||
|
|
||||||
|
par_lsv = tmp->value().as_long();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned PEIdent::test_width(Design*des, NetScope*scope,
|
unsigned PEIdent::test_width(Design*des, NetScope*scope,
|
||||||
unsigned min, unsigned lval,
|
unsigned min, unsigned lval,
|
||||||
bool&unsized_flag) const
|
bool&unsized_flag) const
|
||||||
|
|
@ -1094,6 +1139,131 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static verinum param_part_select_bits(const verinum&par_val, long wid,
|
||||||
|
long lsv, long par_lsv)
|
||||||
|
{
|
||||||
|
verinum result (verinum::Vx, wid, true);
|
||||||
|
|
||||||
|
for (long idx = 0 ; idx < wid ; idx += 1) {
|
||||||
|
long off = idx + lsv - par_lsv;
|
||||||
|
if (off < 0)
|
||||||
|
result.set(idx, verinum::Vx);
|
||||||
|
else if (off < (long)par_val.len())
|
||||||
|
result.set(idx, par_val.get(off));
|
||||||
|
else if (par_val.is_string()) // Pad strings with nulls.
|
||||||
|
result.set(idx, verinum::V0);
|
||||||
|
else if (par_val.has_len()) // Pad sized parameters with X
|
||||||
|
result.set(idx, verinum::Vx);
|
||||||
|
else // Unsized parameters are "infinite" width.
|
||||||
|
result.set(idx, sign_bit(par_val));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the input is a string, and the part select is working on
|
||||||
|
// byte boundaries, then make the result into a string.
|
||||||
|
if (par_val.is_string() && (labs(lsv-par_lsv)%8 == 0) && (wid%8 == 0))
|
||||||
|
return result.as_string();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetExpr* PEIdent::elaborate_expr_param_part_(Design*des, NetScope*scope,
|
||||||
|
const NetExpr*par,
|
||||||
|
NetScope*found_in,
|
||||||
|
const NetExpr*par_msb,
|
||||||
|
const NetExpr*par_lsb) const
|
||||||
|
{
|
||||||
|
long msv, lsv;
|
||||||
|
bool flag = calculate_parts_(des, scope, msv, lsv);
|
||||||
|
if (!flag)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
long par_msv, par_lsv;
|
||||||
|
flag = calculate_param_range_(des, scope, par_msb, par_msv, par_lsb, par_lsv);
|
||||||
|
if (!flag)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Notice that the par_msv is not used is this function other
|
||||||
|
// then for this test. It is used to tell the direction that
|
||||||
|
// the bits are numbers, so that we can make sure the
|
||||||
|
// direction matches the part select direction. After that,
|
||||||
|
// we only need the par_lsv.
|
||||||
|
if (msv>lsv && par_msv<par_lsv || msv<lsv && par_msv>=par_lsv) {
|
||||||
|
cerr << get_fileline() << ": error: Part select "
|
||||||
|
<< "[" << msv << ":" << lsv << "] is out of order." << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
long wid = 1 + labs(msv-lsv);
|
||||||
|
|
||||||
|
if (debug_elaborate)
|
||||||
|
cerr << get_fileline() << ": debug: Calculate part select "
|
||||||
|
<< "[" << msv << ":" << lsv << "] from range "
|
||||||
|
<< "[" << par_msv << ":" << par_lsv << "]." << endl;
|
||||||
|
|
||||||
|
const NetEConst*par_ex = dynamic_cast<const NetEConst*> (par);
|
||||||
|
ivl_assert(*this, par_ex);
|
||||||
|
|
||||||
|
verinum result = param_part_select_bits(par_ex->value(), wid, lsv, par_lsv);
|
||||||
|
NetEConst*result_ex = new NetEConst(result);
|
||||||
|
result_ex->set_line(*this);
|
||||||
|
|
||||||
|
return result_ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope,
|
||||||
|
const NetExpr*par,
|
||||||
|
NetScope*found_in,
|
||||||
|
const NetExpr*par_msb,
|
||||||
|
const NetExpr*par_lsb) const
|
||||||
|
{
|
||||||
|
|
||||||
|
long par_msv, par_lsv;
|
||||||
|
bool flag = calculate_param_range_(des, scope, par_msb, par_msv, par_lsb, par_lsv);
|
||||||
|
if (!flag)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
NetExpr*base = calculate_up_do_base_(des, scope);
|
||||||
|
if (base == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
unsigned long wid = 0;
|
||||||
|
calculate_up_do_width_(des, scope, wid);
|
||||||
|
|
||||||
|
const NetEConst*par_ex = dynamic_cast<const NetEConst*> (par);
|
||||||
|
ivl_assert(*this, par_ex);
|
||||||
|
|
||||||
|
if (debug_elaborate)
|
||||||
|
cerr << get_fileline() << ": debug: Calculate part select "
|
||||||
|
<< "[" << *base << "+:" << wid << "] from range "
|
||||||
|
<< "[" << par_msv << ":" << par_lsv << "]." << endl;
|
||||||
|
|
||||||
|
// Handle the special case that the base is constant. In this
|
||||||
|
// case, just precalculate the entire constant result.
|
||||||
|
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
|
||||||
|
long lsv = base_c->value().as_long();
|
||||||
|
|
||||||
|
// Watch out for reversed bit numbering. We're making
|
||||||
|
// the part select from LSB to MSB.
|
||||||
|
if (par_msv < par_lsv)
|
||||||
|
lsv = lsv - wid + 1;
|
||||||
|
|
||||||
|
verinum result = param_part_select_bits(par_ex->value(), wid,
|
||||||
|
lsv, par_lsv);
|
||||||
|
NetEConst*result_ex = new NetEConst(result);
|
||||||
|
result_ex->set_line(*this);
|
||||||
|
return result_ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((par_msb < par_lsb) && (wid>1))
|
||||||
|
base = make_add_expr(base, 1-(long)wid);
|
||||||
|
|
||||||
|
NetExpr*tmp = par->dup_expr();
|
||||||
|
tmp = new NetESelect(tmp, base, wid);
|
||||||
|
tmp->set_line(*this);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle the case that the identifier is a parameter reference. The
|
* Handle the case that the identifier is a parameter reference. The
|
||||||
* parameter expression has already been located for us (as the par
|
* parameter expression has already been located for us (as the par
|
||||||
|
|
@ -1106,84 +1276,29 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des,
|
||||||
const NetExpr*par_msb,
|
const NetExpr*par_msb,
|
||||||
const NetExpr*par_lsb) const
|
const NetExpr*par_lsb) const
|
||||||
{
|
{
|
||||||
NetExpr*tmp = par->dup_expr();
|
|
||||||
|
|
||||||
const name_component_t&name_tail = path_.back();
|
const name_component_t&name_tail = path_.back();
|
||||||
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
|
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
|
||||||
if (!name_tail.index.empty())
|
if (!name_tail.index.empty())
|
||||||
use_sel = name_tail.index.back().sel;
|
use_sel = name_tail.index.back().sel;
|
||||||
|
|
||||||
if (use_sel == index_component_t::SEL_PART) {
|
// NOTE TO SELF: This is the way I want to see this code
|
||||||
ivl_assert(*this, !name_tail.index.empty());
|
// structured. This closely follows the structure of the
|
||||||
const index_component_t&index_tail = name_tail.index.back();
|
// elaborate_expr_net_ code, which splits all the various
|
||||||
ivl_assert(*this, index_tail.msb);
|
// selects to different methods.
|
||||||
ivl_assert(*this, index_tail.lsb);
|
if (use_sel == index_component_t::SEL_PART)
|
||||||
|
return elaborate_expr_param_part_(des, scope, par, found_in,
|
||||||
|
par_msb, par_lsb);
|
||||||
|
|
||||||
/* If the identifier has a part select, we support
|
if (use_sel == index_component_t::SEL_IDX_UP)
|
||||||
it by pulling the right bits out and making a
|
return elaborate_expr_param_idx_up_(des, scope, par, found_in,
|
||||||
sized unsigned constant. This code assumes the
|
par_msb, par_lsb);
|
||||||
lsb of a parameter is 0 and the msb is the
|
|
||||||
width of the parameter. */
|
|
||||||
|
|
||||||
verinum*lsn = index_tail.lsb->eval_const(des, scope);
|
// NOTE TO SELF (continued): The code below should be
|
||||||
verinum*msn = index_tail.msb->eval_const(des, scope);
|
// rewritten in the above format, as I get to it.
|
||||||
if ((lsn == 0) || (msn == 0)) {
|
|
||||||
cerr << get_fileline() << ": error: "
|
|
||||||
"Part select expressions must be "
|
|
||||||
"constant expressions." << endl;
|
|
||||||
des->errors += 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
long lsb = lsn->as_long();
|
NetExpr*tmp = par->dup_expr();
|
||||||
long msb = msn->as_long();
|
|
||||||
if ((lsb < 0) || (msb < lsb)) {
|
|
||||||
cerr << get_fileline() << ": error: invalid part "
|
|
||||||
<< "select: " << path_
|
|
||||||
<< "["<<msb<<":"<<lsb<<"]" << endl;
|
|
||||||
des->errors += 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
unsigned long ulsb=lsb;
|
|
||||||
unsigned long umsb=msb;
|
|
||||||
|
|
||||||
NetEConst*le = dynamic_cast<NetEConst*>(tmp);
|
if (use_sel == index_component_t::SEL_IDX_DO) {
|
||||||
assert(le);
|
|
||||||
|
|
||||||
verinum result (verinum::V0, msb-lsb+1, true);
|
|
||||||
verinum exl = le->value();
|
|
||||||
|
|
||||||
/* Pull the bits from the parameter, one at a
|
|
||||||
time. If the bit is within the range, simply
|
|
||||||
copy it to the result. If the bit is outside
|
|
||||||
the range, we sign extend signed unsized
|
|
||||||
numbers, zero extend unsigned unsigned numbers,
|
|
||||||
and X extend sized numbers. */
|
|
||||||
for (unsigned long idx = ulsb ; idx <= umsb ; idx += 1) {
|
|
||||||
if (idx < exl.len())
|
|
||||||
result.set(idx-lsb, exl.get(idx));
|
|
||||||
else if (exl.is_string())
|
|
||||||
result.set(idx-lsb, verinum::V0);
|
|
||||||
else if (exl.has_len())
|
|
||||||
result.set(idx-lsb, verinum::Vx);
|
|
||||||
else if (exl.has_sign())
|
|
||||||
result.set(idx-lsb, exl.get(exl.len()-1));
|
|
||||||
else
|
|
||||||
result.set(idx-lsb, verinum::V0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the input is a string, and the part select
|
|
||||||
is working on byte boundaries, then the result
|
|
||||||
can be made into a string. */
|
|
||||||
if (exl.is_string()
|
|
||||||
&& (lsb%8 == 0)
|
|
||||||
&& (result.len()%8 == 0))
|
|
||||||
result = verinum(result.as_string());
|
|
||||||
|
|
||||||
delete tmp;
|
|
||||||
tmp = new NetEConst(result);
|
|
||||||
|
|
||||||
} else if (use_sel == index_component_t::SEL_IDX_UP || use_sel == index_component_t::SEL_IDX_DO) {
|
|
||||||
|
|
||||||
ivl_assert(*this, !name_tail.index.empty());
|
ivl_assert(*this, !name_tail.index.empty());
|
||||||
const index_component_t&index_tail = name_tail.index.back();
|
const index_component_t&index_tail = name_tail.index.back();
|
||||||
|
|
@ -1370,8 +1485,7 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
|
||||||
// Special case: The index is out of range, so the value
|
// Special case: The index is out of range, so the value
|
||||||
// of this expression is a 'bx vector the width of a word.
|
// of this expression is a 'bx vector the width of a word.
|
||||||
if (!net->array_index_is_valid(addr)) {
|
if (!net->array_index_is_valid(addr)) {
|
||||||
verinum xxx (verinum::Vx, net->vector_width());
|
NetEConst*resx = make_const_x(net->vector_width());
|
||||||
NetEConst*resx = new NetEConst(xxx);
|
|
||||||
resx->set_line(*this);
|
resx->set_line(*this);
|
||||||
delete word_index;
|
delete word_index;
|
||||||
return resx;
|
return resx;
|
||||||
|
|
@ -1437,16 +1551,7 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
|
||||||
negative values. However, the width that they represent is
|
negative values. However, the width that they represent is
|
||||||
unsigned. Remember that any order is possible,
|
unsigned. Remember that any order is possible,
|
||||||
i.e., [1:0], [-4:6], etc. */
|
i.e., [1:0], [-4:6], etc. */
|
||||||
unsigned long wid = 1 + ((msv>lsv)? (msv-lsv) : (lsv-msv));
|
unsigned long wid = 1 + labs(msv-lsv);
|
||||||
if (wid > net->vector_width()) {
|
|
||||||
cerr << get_fileline() << ": error: part select ["
|
|
||||||
<< msv << ":" << lsv << "] out of range." << endl;
|
|
||||||
des->errors += 1;
|
|
||||||
//delete lsn;
|
|
||||||
//delete msn;
|
|
||||||
return net;
|
|
||||||
}
|
|
||||||
ivl_assert(*this, wid <= net->vector_width());
|
|
||||||
|
|
||||||
if (net->sig()->sb_to_idx(msv) < net->sig()->sb_to_idx(lsv)) {
|
if (net->sig()->sb_to_idx(msv) < net->sig()->sb_to_idx(lsv)) {
|
||||||
cerr << get_fileline() << ": error: part select ["
|
cerr << get_fileline() << ": error: part select ["
|
||||||
|
|
@ -1457,43 +1562,88 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
|
||||||
return net;
|
return net;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long sb_lsb = net->sig()->sb_to_idx(lsv);
|
||||||
if (net->sig()->sb_to_idx(msv) >= (signed) net->vector_width()) {
|
long sb_msb = net->sig()->sb_to_idx(msv);
|
||||||
cerr << get_fileline() << ": error: part select ["
|
|
||||||
<< msv << ":" << lsv << "] out of range." << endl;
|
|
||||||
des->errors += 1;
|
|
||||||
//delete lsn;
|
|
||||||
//delete msn;
|
|
||||||
return net;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the part select covers exactly the entire
|
// If the part select covers exactly the entire
|
||||||
// vector, then do not bother with it. Return the
|
// vector, then do not bother with it. Return the
|
||||||
// signal itself.
|
// signal itself.
|
||||||
if (net->sig()->sb_to_idx(lsv) == 0 && wid == net->vector_width())
|
if (sb_lsb == 0 && wid == net->vector_width())
|
||||||
return net;
|
return net;
|
||||||
|
|
||||||
NetExpr*ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv)));
|
// If the part select covers NONE of the vector, then return a
|
||||||
|
// constant X.
|
||||||
|
|
||||||
|
if ((sb_lsb >= (signed) net->vector_width()) || (sb_msb < 0)) {
|
||||||
|
NetEConst*tmp = make_const_x(wid);
|
||||||
|
tmp->set_line(*this);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the part select is entirely within the vector, then make
|
||||||
|
// a simple part select.
|
||||||
|
if (sb_lsb >= 0 && sb_msb < (signed)net->vector_width()) {
|
||||||
|
NetExpr*ex = new NetEConst(verinum(sb_lsb));
|
||||||
NetESelect*ss = new NetESelect(net, ex, wid);
|
NetESelect*ss = new NetESelect(net, ex, wid);
|
||||||
ss->set_line(*this);
|
ss->set_line(*this);
|
||||||
|
|
||||||
return ss;
|
return ss;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now the hard stuff. The part select is falling off at least
|
||||||
|
// one end. We're going to need a NetEConcat to mix the
|
||||||
|
// selection with overrun.
|
||||||
|
|
||||||
|
NetEConst*bot = 0;
|
||||||
|
if (sb_lsb < 0) {
|
||||||
|
bot = make_const_x( 0-sb_lsb );
|
||||||
|
bot->set_line(*this);
|
||||||
|
sb_lsb = 0;
|
||||||
|
}
|
||||||
|
NetEConst*top = 0;
|
||||||
|
if (sb_msb >= (signed)net->vector_width()) {
|
||||||
|
top = make_const_x( 1+sb_msb-net->vector_width() );
|
||||||
|
top->set_line(*this);
|
||||||
|
sb_msb = net->vector_width()-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned concat_count = 1;
|
||||||
|
if (bot) concat_count += 1;
|
||||||
|
if (top) concat_count += 1;
|
||||||
|
|
||||||
|
NetEConcat*concat = new NetEConcat(concat_count);
|
||||||
|
concat->set_line(*this);
|
||||||
|
|
||||||
|
if (bot) {
|
||||||
|
concat_count -= 1;
|
||||||
|
concat->set(concat_count, bot);
|
||||||
|
}
|
||||||
|
if (sb_lsb == 0 && sb_msb+1 == (signed)net->vector_width()) {
|
||||||
|
concat_count -= 1;
|
||||||
|
concat->set(concat_count, net);
|
||||||
|
} else {
|
||||||
|
NetExpr*ex = new NetEConst(verinum(sb_lsb));
|
||||||
|
ex->set_line(*this);
|
||||||
|
NetESelect*ss = new NetESelect(net, ex, 1+sb_msb-sb_lsb);
|
||||||
|
ss->set_line(*this);
|
||||||
|
concat_count -= 1;
|
||||||
|
concat->set(concat_count, ss);
|
||||||
|
}
|
||||||
|
if (top) {
|
||||||
|
concat_count -= 1;
|
||||||
|
concat->set(concat_count, top);
|
||||||
|
}
|
||||||
|
ivl_assert(*this, concat_count==0);
|
||||||
|
|
||||||
|
return concat;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Part select indexed up, i.e. net[<m> +: <l>]
|
* Part select indexed up, i.e. net[<m> +: <l>]
|
||||||
*/
|
*/
|
||||||
NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
|
NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
|
||||||
NetESignal*net, NetScope*found_in) const
|
NetESignal*net, NetScope*found_in) const
|
||||||
{
|
{
|
||||||
const name_component_t&name_tail = path_.back();
|
NetExpr*base = calculate_up_do_base_(des, scope);
|
||||||
ivl_assert(*this, !name_tail.index.empty());
|
|
||||||
|
|
||||||
const index_component_t&index_tail = name_tail.index.back();
|
|
||||||
ivl_assert(*this, index_tail.lsb != 0);
|
|
||||||
ivl_assert(*this, index_tail.msb != 0);
|
|
||||||
|
|
||||||
NetExpr*base = elab_and_eval(des, scope, index_tail.msb, -1);
|
|
||||||
|
|
||||||
unsigned long wid = 0;
|
unsigned long wid = 0;
|
||||||
calculate_up_do_width_(des, scope, wid);
|
calculate_up_do_width_(des, scope, wid);
|
||||||
|
|
@ -1618,8 +1768,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
|
||||||
/* The bit select is out of range of the
|
/* The bit select is out of range of the
|
||||||
vector. This is legal, but returns a
|
vector. This is legal, but returns a
|
||||||
constant 1'bx value. */
|
constant 1'bx value. */
|
||||||
verinum x (verinum::Vx);
|
NetEConst*tmp = make_const_x(1);
|
||||||
NetEConst*tmp = new NetEConst(x);
|
|
||||||
tmp->set_line(*this);
|
tmp->set_line(*this);
|
||||||
|
|
||||||
cerr << get_fileline() << ": warning: Bit select ["
|
cerr << get_fileline() << ": warning: Bit select ["
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,16 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
|
||||||
tmp->low_expr = 0;
|
tmp->low_expr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (range->high_expr) {
|
if (range->high_expr && range->high_expr==range->low_expr) {
|
||||||
|
// Detect the special case of a "point"
|
||||||
|
// range. These are called out by setting the high
|
||||||
|
// and low expression ranges to the same
|
||||||
|
// expression. The exclude_flags should be false
|
||||||
|
// in this case
|
||||||
|
ivl_assert(*range->high_expr, tmp->low_open_flag==false && tmp->high_open_flag==false);
|
||||||
|
tmp->high_expr = tmp->low_expr;
|
||||||
|
|
||||||
|
} else if (range->high_expr) {
|
||||||
tmp->high_expr = elab_and_eval(des, scope, range->high_expr, -1);
|
tmp->high_expr = elab_and_eval(des, scope, range->high_expr, -1);
|
||||||
ivl_assert(*range->high_expr, tmp->high_expr);
|
ivl_assert(*range->high_expr, tmp->high_expr);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -123,6 +123,13 @@ NetExpr* make_sub_expr(long val, NetExpr*expr)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetEConst* make_const_x(unsigned long wid)
|
||||||
|
{
|
||||||
|
verinum xxx (verinum::Vx, wid);
|
||||||
|
NetEConst*resx = new NetEConst(xxx);
|
||||||
|
return resx;
|
||||||
|
}
|
||||||
|
|
||||||
NetExpr* condition_reduce(NetExpr*expr)
|
NetExpr* condition_reduce(NetExpr*expr)
|
||||||
{
|
{
|
||||||
if (expr->expr_width() == 1)
|
if (expr->expr_width() == 1)
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,11 @@ extern NetNet*add_to_net(Design*des, NetNet*sig, long val);
|
||||||
extern NetExpr*make_add_expr(NetExpr*expr, long val);
|
extern NetExpr*make_add_expr(NetExpr*expr, long val);
|
||||||
extern NetExpr*make_sub_expr(long val, NetExpr*expr);
|
extern NetExpr*make_sub_expr(long val, NetExpr*expr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make a NetEConst object that contains only X bits.
|
||||||
|
*/
|
||||||
|
extern NetEConst*make_const_x(unsigned long wid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In some cases the lval is accessible as a pointer to the head of
|
* In some cases the lval is accessible as a pointer to the head of
|
||||||
* a list of NetAssign_ objects. This function returns the width of
|
* a list of NetAssign_ objects. This function returns the width of
|
||||||
|
|
|
||||||
8
parse.y
8
parse.y
|
|
@ -323,10 +323,15 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
|
||||||
%left K_POW
|
%left K_POW
|
||||||
%left UNARY_PREC
|
%left UNARY_PREC
|
||||||
|
|
||||||
|
|
||||||
/* to resolve dangling else ambiguity. */
|
/* to resolve dangling else ambiguity. */
|
||||||
%nonassoc less_than_K_else
|
%nonassoc less_than_K_else
|
||||||
%nonassoc K_else
|
%nonassoc K_else
|
||||||
|
|
||||||
|
/* to resolve exclude (... ambiguity */
|
||||||
|
%nonassoc '('
|
||||||
|
%nonassoc K_exclude
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
/* A degenerate source file can be completely empty. */
|
/* A degenerate source file can be completely empty. */
|
||||||
|
|
@ -2432,7 +2437,8 @@ parameter_value_range
|
||||||
{ $$ = pform_parameter_value_range($1, true, $3, false, $5); }
|
{ $$ = pform_parameter_value_range($1, true, $3, false, $5); }
|
||||||
| from_exclude '(' value_range_expression ':' value_range_expression ')'
|
| from_exclude '(' value_range_expression ':' value_range_expression ')'
|
||||||
{ $$ = pform_parameter_value_range($1, true, $3, true, $5); }
|
{ $$ = pform_parameter_value_range($1, true, $3, true, $5); }
|
||||||
/* | K_exclude expression */
|
| K_exclude expression
|
||||||
|
{ $$ = pform_parameter_value_range(true, false, $2, false, $2); }
|
||||||
;
|
;
|
||||||
|
|
||||||
value_range_expression
|
value_range_expression
|
||||||
|
|
|
||||||
|
|
@ -285,10 +285,17 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||||
word_ex = 0;
|
word_ex = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (word_ex)
|
if (word_ex) {
|
||||||
break;
|
struct vector_info av;
|
||||||
|
av = draw_eval_expr(word_ex, STUFF_OK_XZ);
|
||||||
snprintf(buffer, sizeof buffer, "&A<v%p, %u>", sig, use_word);
|
snprintf(buffer, sizeof buffer,
|
||||||
|
"&A<v%p, T<%u,%u,u>>", sig, av.base, av.wid);
|
||||||
|
args[idx].vec = av;
|
||||||
|
args[idx].vec_flag = 1;
|
||||||
|
} else {
|
||||||
|
snprintf(buffer, sizeof buffer,
|
||||||
|
"&A<v%p, %u>", sig, use_word);
|
||||||
|
}
|
||||||
args[idx].text = strdup(buffer);
|
args[idx].text = strdup(buffer);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
* Copyright (c) 1999-2008 Stephen Williams (steve@icarus.com)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -16,45 +16,12 @@
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_CVS_IDENT
|
|
||||||
#ident "$Id: sys_finish.c,v 1.11 2007/04/09 22:49:33 steve Exp $"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "vpi_config.h"
|
#include "vpi_config.h"
|
||||||
|
|
||||||
#include "vpi_user.h"
|
#include "vpi_user.h"
|
||||||
|
#include "sys_priv.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static PLI_INT32 sys_finish_compiletf(PLI_BYTE8 *name)
|
|
||||||
{
|
|
||||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
|
||||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
|
||||||
vpiHandle arg;
|
|
||||||
|
|
||||||
/* The argument is optional. */
|
|
||||||
if (argv == 0) return 0;
|
|
||||||
arg = vpi_scan(argv);
|
|
||||||
|
|
||||||
/* A string diagnostic message level makes no sense. */
|
|
||||||
if (vpi_get(vpiType, arg) == vpiConstant &&
|
|
||||||
vpi_get(vpiConstType, arg) == vpiStringConst) {
|
|
||||||
vpi_printf("Error: %s does not take a string argument.\n", name);
|
|
||||||
vpi_control(vpiFinish, 1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* These functions take at most one argument (diagnostic message). */
|
|
||||||
arg = vpi_scan(argv);
|
|
||||||
if (arg != 0) {
|
|
||||||
vpi_printf("Error: %s takes at most one argument.\n", name);
|
|
||||||
vpi_control(vpiFinish, 1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* vpi_scan returning 0 (NULL) has already freed argv. */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PLI_INT32 sys_finish_calltf(PLI_BYTE8 *name)
|
static PLI_INT32 sys_finish_calltf(PLI_BYTE8 *name)
|
||||||
{
|
{
|
||||||
vpiHandle callh, argv, arg;
|
vpiHandle callh, argv, arg;
|
||||||
|
|
@ -88,55 +55,16 @@ void sys_finish_register()
|
||||||
tf_data.type = vpiSysTask;
|
tf_data.type = vpiSysTask;
|
||||||
tf_data.tfname = "$finish";
|
tf_data.tfname = "$finish";
|
||||||
tf_data.calltf = sys_finish_calltf;
|
tf_data.calltf = sys_finish_calltf;
|
||||||
tf_data.compiletf = sys_finish_compiletf;
|
tf_data.compiletf = sys_one_opt_numeric_arg_compiletf;
|
||||||
tf_data.sizetf = 0;
|
tf_data.sizetf = 0;
|
||||||
tf_data.user_data = (PLI_BYTE8*)"$finish";
|
tf_data.user_data = "$finish";
|
||||||
vpi_register_systf(&tf_data);
|
vpi_register_systf(&tf_data);
|
||||||
|
|
||||||
tf_data.type = vpiSysTask;
|
tf_data.type = vpiSysTask;
|
||||||
tf_data.tfname = "$stop";
|
tf_data.tfname = "$stop";
|
||||||
tf_data.calltf = sys_finish_calltf;
|
tf_data.calltf = sys_finish_calltf;
|
||||||
tf_data.compiletf = sys_finish_compiletf;
|
tf_data.compiletf = sys_one_opt_numeric_arg_compiletf;
|
||||||
tf_data.sizetf = 0;
|
tf_data.sizetf = 0;
|
||||||
tf_data.user_data = (PLI_BYTE8*)"$stop";
|
tf_data.user_data = "$stop";
|
||||||
vpi_register_systf(&tf_data);
|
vpi_register_systf(&tf_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* $Log: sys_finish.c,v $
|
|
||||||
* Revision 1.11 2007/04/09 22:49:33 steve
|
|
||||||
* More strict use of PLI_BYTE8 type.
|
|
||||||
*
|
|
||||||
* Revision 1.10 2006/10/30 22:45:37 steve
|
|
||||||
* Updates for Cygwin portability (pr1585922)
|
|
||||||
*
|
|
||||||
* Revision 1.9 2004/01/21 01:22:53 steve
|
|
||||||
* Give the vip directory its own configure and vpi_config.h
|
|
||||||
*
|
|
||||||
* Revision 1.8 2003/02/21 03:24:03 steve
|
|
||||||
* Make the $stop system task really vpiStop.
|
|
||||||
*
|
|
||||||
* Revision 1.7 2002/08/12 01:35:04 steve
|
|
||||||
* conditional ident string using autoconfig.
|
|
||||||
*
|
|
||||||
* Revision 1.6 2001/07/25 03:10:50 steve
|
|
||||||
* Create a config.h.in file to hold all the config
|
|
||||||
* junk, and support gcc 3.0. (Stephan Boettcher)
|
|
||||||
*
|
|
||||||
* Revision 1.5 2001/01/01 19:33:44 steve
|
|
||||||
* Add $stop that does a finish.
|
|
||||||
*
|
|
||||||
* Revision 1.4 2000/02/23 02:56:56 steve
|
|
||||||
* Macintosh compilers do not support ident.
|
|
||||||
*
|
|
||||||
* Revision 1.3 1999/08/28 02:10:44 steve
|
|
||||||
* Call the right vpiFinish code.
|
|
||||||
*
|
|
||||||
* Revision 1.2 1999/08/19 02:51:03 steve
|
|
||||||
* Add vpi_sim_control
|
|
||||||
*
|
|
||||||
* Revision 1.1 1999/08/15 01:23:56 steve
|
|
||||||
* Convert vvm to implement system tasks with vpi.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,54 +20,13 @@
|
||||||
#include <vpi_user.h>
|
#include <vpi_user.h>
|
||||||
#include "sys_priv.h"
|
#include "sys_priv.h"
|
||||||
|
|
||||||
/*
|
static PLI_INT32 finish_and_return_calltf(PLI_BYTE8* name)
|
||||||
* Routine to finish the simulation and return a value to the
|
|
||||||
* calling environment.
|
|
||||||
*/
|
|
||||||
static PLI_INT32 finish_and_return_compiletf(PLI_BYTE8* ud)
|
|
||||||
{
|
|
||||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
|
||||||
assert(callh);
|
|
||||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
|
||||||
(void) ud; /* Not used! */
|
|
||||||
|
|
||||||
/* We must have at least one argument. */
|
|
||||||
if (argv == 0) {
|
|
||||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
|
||||||
(int)vpi_get(vpiLineNo, callh));
|
|
||||||
vpi_printf("$finish_and_return requires an argument.\n");
|
|
||||||
vpi_control(vpiFinish, 1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This must be a numeric argument. */
|
|
||||||
if (! is_numeric_obj(vpi_scan(argv))) {
|
|
||||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
|
||||||
(int)vpi_get(vpiLineNo, callh));
|
|
||||||
vpi_printf("The argument to $finish_and_return must be numeric.\n");
|
|
||||||
vpi_control(vpiFinish, 1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We can only have one argument. */
|
|
||||||
if (vpi_scan(argv) != 0) {
|
|
||||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
|
||||||
(int)vpi_get(vpiLineNo, callh));
|
|
||||||
vpi_printf("$finish_and_return takes only a single argument.\n");
|
|
||||||
vpi_control(vpiFinish, 1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PLI_INT32 finish_and_return_calltf(PLI_BYTE8* ud)
|
|
||||||
{
|
{
|
||||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
vpiHandle arg;
|
vpiHandle arg;
|
||||||
s_vpi_value val;
|
s_vpi_value val;
|
||||||
(void) ud; /* Not used! */
|
(void) name; /* Not used! */
|
||||||
|
|
||||||
/* Get the return value. */
|
/* Get the return value. */
|
||||||
arg = vpi_scan(argv);
|
arg = vpi_scan(argv);
|
||||||
|
|
@ -92,9 +51,9 @@ void sys_special_register(void)
|
||||||
|
|
||||||
tf_data.type = vpiSysTask;
|
tf_data.type = vpiSysTask;
|
||||||
tf_data.calltf = finish_and_return_calltf;
|
tf_data.calltf = finish_and_return_calltf;
|
||||||
tf_data.compiletf = finish_and_return_compiletf;
|
tf_data.compiletf = sys_one_numeric_arg_compiletf;
|
||||||
tf_data.sizetf = 0;
|
tf_data.sizetf = 0;
|
||||||
tf_data.tfname = "$finish_and_return";
|
tf_data.tfname = "$finish_and_return";
|
||||||
tf_data.user_data = 0;
|
tf_data.user_data = "$finish_and_return";
|
||||||
vpi_register_systf(&tf_data);
|
vpi_register_systf(&tf_data);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -782,7 +782,7 @@ void sys_lxt_register()
|
||||||
tf_data.type = vpiSysTask;
|
tf_data.type = vpiSysTask;
|
||||||
tf_data.tfname = "$dumplimit";
|
tf_data.tfname = "$dumplimit";
|
||||||
tf_data.calltf = sys_dumplimit_calltf;
|
tf_data.calltf = sys_dumplimit_calltf;
|
||||||
tf_data.compiletf = sys_dumplimit_compiletf;
|
tf_data.compiletf = sys_one_numeric_arg_compiletf;
|
||||||
tf_data.sizetf = 0;
|
tf_data.sizetf = 0;
|
||||||
tf_data.user_data = "$dumplimit";
|
tf_data.user_data = "$dumplimit";
|
||||||
vpi_register_systf(&tf_data);
|
vpi_register_systf(&tf_data);
|
||||||
|
|
|
||||||
|
|
@ -797,7 +797,7 @@ void sys_lxt2_register()
|
||||||
tf_data.type = vpiSysTask;
|
tf_data.type = vpiSysTask;
|
||||||
tf_data.tfname = "$dumplimit";
|
tf_data.tfname = "$dumplimit";
|
||||||
tf_data.calltf = sys_dumplimit_calltf;
|
tf_data.calltf = sys_dumplimit_calltf;
|
||||||
tf_data.compiletf = sys_dumplimit_compiletf;
|
tf_data.compiletf = sys_one_numeric_arg_compiletf;
|
||||||
tf_data.sizetf = 0;
|
tf_data.sizetf = 0;
|
||||||
tf_data.user_data = "$dumplimit";
|
tf_data.user_data = "$dumplimit";
|
||||||
vpi_register_systf(&tf_data);
|
vpi_register_systf(&tf_data);
|
||||||
|
|
|
||||||
106
vpi/sys_priv.c
106
vpi/sys_priv.c
|
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
#include "sys_priv.h"
|
#include "sys_priv.h"
|
||||||
|
|
||||||
PLI_UINT64 timerec_to_time64(const struct t_vpi_time*time)
|
PLI_UINT64 timerec_to_time64(const struct t_vpi_time*time)
|
||||||
|
|
@ -129,3 +130,108 @@ vpiHandle sys_func_module(vpiHandle obj)
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Standard compiletf routines.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* For system functions that do not take an argument. */
|
||||||
|
PLI_INT32 sys_no_arg_compiletf(PLI_BYTE8 *name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
|
||||||
|
/* Make sure there are no arguments. */
|
||||||
|
if (argv != 0) {
|
||||||
|
char msg [64];
|
||||||
|
snprintf(msg, 64, "ERROR: %s line %d:",
|
||||||
|
vpi_get_str(vpiFile, callh),
|
||||||
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
|
|
||||||
|
unsigned argc = 0;
|
||||||
|
while (vpi_scan(argv)) argc += 1;
|
||||||
|
|
||||||
|
vpi_printf("%s %s does not take an argument.\n", msg, name);
|
||||||
|
vpi_printf("%*s Found %u extra argument%s.\n",
|
||||||
|
strlen(msg), " ", argc, argc == 1 ? "" : "s");
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For system functions that take a single numeric argument. */
|
||||||
|
PLI_INT32 sys_one_numeric_arg_compiletf(PLI_BYTE8 *name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
|
||||||
|
/* Check that there is an argument and that it is numeric. */
|
||||||
|
if (argv == 0) {
|
||||||
|
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||||
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
|
vpi_printf("%s requires a single numeric argument.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! is_numeric_obj(vpi_scan(argv))) {
|
||||||
|
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||||
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
|
vpi_printf("%s's argument must be numeric.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure there are no extra arguments. */
|
||||||
|
if (vpi_scan(argv) != 0) {
|
||||||
|
char msg [64];
|
||||||
|
snprintf(msg, 64, "ERROR: %s line %d:",
|
||||||
|
vpi_get_str(vpiFile, callh),
|
||||||
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
|
|
||||||
|
unsigned argc = 1;
|
||||||
|
while (vpi_scan(argv)) argc += 1;
|
||||||
|
|
||||||
|
vpi_printf("%s %s takes a single numeric argument.\n", msg, name);
|
||||||
|
vpi_printf("%*s Found %u extra argument%s.\n",
|
||||||
|
strlen(msg), " ", argc, argc == 1 ? "" : "s");
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For system functions that take a single optional numeric argument. */
|
||||||
|
PLI_INT32 sys_one_opt_numeric_arg_compiletf(PLI_BYTE8 *name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
|
||||||
|
/* The argument is optional so just return if none are found. */
|
||||||
|
if (argv == 0) return 0;
|
||||||
|
|
||||||
|
if (! is_numeric_obj(vpi_scan(argv))) {
|
||||||
|
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||||
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
|
vpi_printf("%s's argument must be numeric.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure there are no extra arguments. */
|
||||||
|
if (vpi_scan(argv) != 0) {
|
||||||
|
char msg [64];
|
||||||
|
snprintf(msg, 64, "ERROR: %s line %d:",
|
||||||
|
vpi_get_str(vpiFile, callh),
|
||||||
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
|
|
||||||
|
unsigned argc = 1;
|
||||||
|
while (vpi_scan(argv)) argc += 1;
|
||||||
|
|
||||||
|
vpi_printf("%s %s takes a single numeric argument.\n", msg, name);
|
||||||
|
vpi_printf("%*s Found %u extra argument%s.\n",
|
||||||
|
strlen(msg), " ", argc, argc == 1 ? "" : "s");
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,4 +50,11 @@ extern unsigned is_string_obj(vpiHandle obj);
|
||||||
|
|
||||||
extern vpiHandle sys_func_module(vpiHandle obj);
|
extern vpiHandle sys_func_module(vpiHandle obj);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The standard compiletf routines.
|
||||||
|
*/
|
||||||
|
extern PLI_INT32 sys_no_arg_compiletf(PLI_BYTE8 *name);
|
||||||
|
extern PLI_INT32 sys_one_numeric_arg_compiletf(PLI_BYTE8 *name);
|
||||||
|
extern PLI_INT32 sys_one_opt_numeric_arg_compiletf(PLI_BYTE8 *name);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ void sys_time_register()
|
||||||
tf_data.tfname = "$time";
|
tf_data.tfname = "$time";
|
||||||
tf_data.sysfunctype = vpiTimeFunc;
|
tf_data.sysfunctype = vpiTimeFunc;
|
||||||
tf_data.calltf = sys_time_calltf;
|
tf_data.calltf = sys_time_calltf;
|
||||||
tf_data.compiletf = 0;
|
tf_data.compiletf = sys_no_arg_compiletf;
|
||||||
tf_data.sizetf = 0;
|
tf_data.sizetf = 0;
|
||||||
tf_data.user_data = "$time";
|
tf_data.user_data = "$time";
|
||||||
vpi_register_systf(&tf_data);
|
vpi_register_systf(&tf_data);
|
||||||
|
|
@ -125,7 +125,7 @@ void sys_time_register()
|
||||||
tf_data.tfname = "$realtime";
|
tf_data.tfname = "$realtime";
|
||||||
tf_data.sysfunctype = vpiRealFunc;
|
tf_data.sysfunctype = vpiRealFunc;
|
||||||
tf_data.calltf = sys_realtime_calltf;
|
tf_data.calltf = sys_realtime_calltf;
|
||||||
tf_data.compiletf = 0;
|
tf_data.compiletf = sys_no_arg_compiletf;
|
||||||
tf_data.sizetf = 0;
|
tf_data.sizetf = 0;
|
||||||
tf_data.user_data = "$realtime";
|
tf_data.user_data = "$realtime";
|
||||||
vpi_register_systf(&tf_data);
|
vpi_register_systf(&tf_data);
|
||||||
|
|
@ -134,7 +134,7 @@ void sys_time_register()
|
||||||
tf_data.tfname = "$stime";
|
tf_data.tfname = "$stime";
|
||||||
tf_data.sysfunctype = vpiIntFunc;
|
tf_data.sysfunctype = vpiIntFunc;
|
||||||
tf_data.calltf = sys_time_calltf;
|
tf_data.calltf = sys_time_calltf;
|
||||||
tf_data.compiletf = 0;
|
tf_data.compiletf = sys_no_arg_compiletf;
|
||||||
tf_data.sizetf = 0;
|
tf_data.sizetf = 0;
|
||||||
tf_data.user_data = "$stime";
|
tf_data.user_data = "$stime";
|
||||||
vpi_register_systf(&tf_data);
|
vpi_register_systf(&tf_data);
|
||||||
|
|
@ -143,7 +143,7 @@ void sys_time_register()
|
||||||
tf_data.tfname = "$simtime";
|
tf_data.tfname = "$simtime";
|
||||||
tf_data.sysfunctype = vpiTimeFunc;
|
tf_data.sysfunctype = vpiTimeFunc;
|
||||||
tf_data.calltf = sys_time_calltf;
|
tf_data.calltf = sys_time_calltf;
|
||||||
tf_data.compiletf = 0;
|
tf_data.compiletf = sys_no_arg_compiletf;
|
||||||
tf_data.sizetf = 0;
|
tf_data.sizetf = 0;
|
||||||
tf_data.user_data = "$simtime";
|
tf_data.user_data = "$simtime";
|
||||||
vpi_register_systf(&tf_data);
|
vpi_register_systf(&tf_data);
|
||||||
|
|
|
||||||
|
|
@ -795,7 +795,7 @@ void sys_vcd_register()
|
||||||
tf_data.type = vpiSysTask;
|
tf_data.type = vpiSysTask;
|
||||||
tf_data.tfname = "$dumplimit";
|
tf_data.tfname = "$dumplimit";
|
||||||
tf_data.calltf = sys_dumplimit_calltf;
|
tf_data.calltf = sys_dumplimit_calltf;
|
||||||
tf_data.compiletf = sys_dumplimit_compiletf;
|
tf_data.compiletf = sys_one_numeric_arg_compiletf;
|
||||||
tf_data.sizetf = 0;
|
tf_data.sizetf = 0;
|
||||||
tf_data.user_data = "$dumplimit";
|
tf_data.user_data = "$dumplimit";
|
||||||
vpi_register_systf(&tf_data);
|
vpi_register_systf(&tf_data);
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ void sys_vcdoff_register()
|
||||||
tf_data.type = vpiSysTask;
|
tf_data.type = vpiSysTask;
|
||||||
tf_data.tfname = "$dumplimit";
|
tf_data.tfname = "$dumplimit";
|
||||||
tf_data.calltf = sys_dummy_calltf;
|
tf_data.calltf = sys_dummy_calltf;
|
||||||
tf_data.compiletf = sys_dumplimit_compiletf;
|
tf_data.compiletf = sys_one_numeric_arg_compiletf;
|
||||||
tf_data.sizetf = 0;
|
tf_data.sizetf = 0;
|
||||||
tf_data.user_data = "$dumplimit";
|
tf_data.user_data = "$dumplimit";
|
||||||
vpi_register_systf(&tf_data);
|
vpi_register_systf(&tf_data);
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
/*
|
/*
|
||||||
* Check that the routines are called with the correct arguments.
|
* Check that the routines are called with the correct arguments.
|
||||||
*/
|
*/
|
||||||
static PLI_INT32 simparam_compiletf(PLI_BYTE8* ud)
|
static PLI_INT32 simparam_compiletf(PLI_BYTE8* name_ext)
|
||||||
{
|
{
|
||||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
assert(callh != 0);
|
assert(callh != 0);
|
||||||
|
|
@ -45,7 +45,7 @@ static PLI_INT32 simparam_compiletf(PLI_BYTE8* ud)
|
||||||
if (argv == 0) {
|
if (argv == 0) {
|
||||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||||
(int)vpi_get(vpiLineNo, callh));
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
vpi_printf("$simparam%s requires an argument.\n", ud);
|
vpi_printf("$simparam%s requires a string argument.\n", name_ext);
|
||||||
vpi_control(vpiFinish, 1);
|
vpi_control(vpiFinish, 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -55,7 +55,8 @@ static PLI_INT32 simparam_compiletf(PLI_BYTE8* ud)
|
||||||
if (! is_string_obj(arg)) {
|
if (! is_string_obj(arg)) {
|
||||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||||
(int)vpi_get(vpiLineNo, callh));
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
vpi_printf("The first argument to $simparam%s must be a string.\n", ud);
|
vpi_printf("The first argument to $simparam%s must be a string.\n",
|
||||||
|
name_ext);
|
||||||
vpi_control(vpiFinish, 1);
|
vpi_control(vpiFinish, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,12 +65,12 @@ static PLI_INT32 simparam_compiletf(PLI_BYTE8* ud)
|
||||||
if (arg == 0) return 0;
|
if (arg == 0) return 0;
|
||||||
|
|
||||||
/* For the string version the default must also be a string. */
|
/* For the string version the default must also be a string. */
|
||||||
if (strcmp(ud, "$str") == 0) {
|
if (strcmp(name_ext, "$str") == 0) {
|
||||||
if (! is_string_obj(arg)) {
|
if (! is_string_obj(arg)) {
|
||||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||||
(int)vpi_get(vpiLineNo, callh));
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
vpi_printf("When provided, the second argument to $simparam%s"
|
vpi_printf("When provided, the second argument to $simparam%s"
|
||||||
"must be a string.\n", ud);
|
"must be a string.\n", name_ext);
|
||||||
vpi_control(vpiFinish, 1);
|
vpi_control(vpiFinish, 1);
|
||||||
}
|
}
|
||||||
/* For the rest the default must be numeric. */
|
/* For the rest the default must be numeric. */
|
||||||
|
|
@ -78,23 +79,32 @@ static PLI_INT32 simparam_compiletf(PLI_BYTE8* ud)
|
||||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||||
(int)vpi_get(vpiLineNo, callh));
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
vpi_printf("When provided, the second argument to $simparam%s"
|
vpi_printf("When provided, the second argument to $simparam%s"
|
||||||
"must be numeric.\n", ud);
|
"must be numeric.\n", name_ext);
|
||||||
vpi_control(vpiFinish, 1);
|
vpi_control(vpiFinish, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We can only have two argument. */
|
/* We can only have two argument. */
|
||||||
if (vpi_scan(argv) != 0) {
|
if (vpi_scan(argv) != 0) {
|
||||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
char msg [64];
|
||||||
|
snprintf(msg, 64, "ERROR: %s line %d:",
|
||||||
|
vpi_get_str(vpiFile, callh),
|
||||||
(int)vpi_get(vpiLineNo, callh));
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
vpi_printf("$simparam%s takes at most two arguments.\n", ud);
|
|
||||||
|
unsigned argc = 1;
|
||||||
|
while (vpi_scan(argv)) argc += 1;
|
||||||
|
|
||||||
|
vpi_printf("%s $simparam%s takes at most two arguments.\n",
|
||||||
|
msg, name_ext);
|
||||||
|
vpi_printf("%*s Found %u extra argument%s.\n",
|
||||||
|
strlen(msg), " ", argc, argc == 1 ? "" : "s");
|
||||||
vpi_control(vpiFinish, 1);
|
vpi_control(vpiFinish, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PLI_INT32 simparam_calltf(PLI_BYTE8* ud)
|
static PLI_INT32 simparam_calltf(PLI_BYTE8* name_ext)
|
||||||
{
|
{
|
||||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
|
@ -153,7 +163,8 @@ static PLI_INT32 simparam_calltf(PLI_BYTE8* ud)
|
||||||
if (! have_def_val) {
|
if (! have_def_val) {
|
||||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||||
(int)vpi_get(vpiLineNo, callh));
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
vpi_printf("unknown parameter name \"%s\".\n", param);
|
vpi_printf("$simparam%s unknown parameter name \"%s\".\n",
|
||||||
|
name_ext, param);
|
||||||
}
|
}
|
||||||
retval = defval;
|
retval = defval;
|
||||||
}
|
}
|
||||||
|
|
@ -168,7 +179,7 @@ static PLI_INT32 simparam_calltf(PLI_BYTE8* ud)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PLI_INT32 simparam_str_calltf(PLI_BYTE8* ud)
|
static PLI_INT32 simparam_str_calltf(PLI_BYTE8* name_ext)
|
||||||
{
|
{
|
||||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
|
@ -217,7 +228,8 @@ static PLI_INT32 simparam_str_calltf(PLI_BYTE8* ud)
|
||||||
if (defval == 0) {
|
if (defval == 0) {
|
||||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||||
(int)vpi_get(vpiLineNo, callh));
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
vpi_printf("unknown parameter name \"%s\".\n", param);
|
vpi_printf("$simparam%s unknown parameter name \"%s\".\n",
|
||||||
|
name_ext, param);
|
||||||
defval = strdup("<error>");
|
defval = strdup("<error>");
|
||||||
}
|
}
|
||||||
retval = defval;
|
retval = defval;
|
||||||
|
|
@ -234,9 +246,9 @@ static PLI_INT32 simparam_str_calltf(PLI_BYTE8* ud)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PLI_INT32 simparam_str_sizetf(PLI_BYTE8* ud)
|
static PLI_INT32 simparam_str_sizetf(PLI_BYTE8* name_ext)
|
||||||
{
|
{
|
||||||
(void) ud; //* Not used! */
|
(void) name_ext; //* Not used! */
|
||||||
|
|
||||||
return MAX_STRING_RESULT; // 128 characters max!
|
return MAX_STRING_RESULT; // 128 characters max!
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -188,25 +188,10 @@ void set_nexus_ident(int nex, const char *id)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since the compiletf routines are all the same they are located here,
|
* Since the compiletf routines are all the same they are located here,
|
||||||
* so we only need a single copy.
|
* so we only need a single copy. Some are generic enough they can use
|
||||||
|
* the ones in sys_priv.c (no arg, one numeric arg.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* $dumpall, $dumpflush, $dumpoff and $dumpon do not take an argument. */
|
|
||||||
PLI_INT32 sys_no_arg_compiletf(PLI_BYTE8 *name)
|
|
||||||
{
|
|
||||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
|
||||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
|
||||||
|
|
||||||
if (argv != 0) {
|
|
||||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
|
||||||
(int)vpi_get(vpiLineNo, callh));
|
|
||||||
vpi_printf("%s does not take an argument.\n", name);
|
|
||||||
vpi_control(vpiFinish, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* $dumpfile takes a single string argument. */
|
/* $dumpfile takes a single string argument. */
|
||||||
PLI_INT32 sys_dumpfile_compiletf(PLI_BYTE8 *name)
|
PLI_INT32 sys_dumpfile_compiletf(PLI_BYTE8 *name)
|
||||||
{
|
{
|
||||||
|
|
@ -217,7 +202,7 @@ PLI_INT32 sys_dumpfile_compiletf(PLI_BYTE8 *name)
|
||||||
if (argv == 0) {
|
if (argv == 0) {
|
||||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||||
(int)vpi_get(vpiLineNo, callh));
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
vpi_printf("%s requires an argument.\n", name);
|
vpi_printf("%s requires a single string argument.\n", name);
|
||||||
vpi_control(vpiFinish, 1);
|
vpi_control(vpiFinish, 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -228,44 +213,19 @@ PLI_INT32 sys_dumpfile_compiletf(PLI_BYTE8 *name)
|
||||||
vpi_control(vpiFinish, 1);
|
vpi_control(vpiFinish, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check that there is only a single argument. */
|
/* Make sure there are no extra arguments. */
|
||||||
if (vpi_scan(argv) != 0) {
|
if (vpi_scan(argv) != 0) {
|
||||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
char msg [64];
|
||||||
|
snprintf(msg, 64, "ERROR: %s line %d:",
|
||||||
|
vpi_get_str(vpiFile, callh),
|
||||||
(int)vpi_get(vpiLineNo, callh));
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
vpi_printf("%s takes a single argument.\n", name);
|
|
||||||
vpi_control(vpiFinish, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
unsigned argc = 1;
|
||||||
}
|
while (vpi_scan(argv)) argc += 1;
|
||||||
|
|
||||||
/* $dumplimit takes a single numeric argument. */
|
vpi_printf("%s %s takes a single string argument.\n", msg, name);
|
||||||
PLI_INT32 sys_dumplimit_compiletf(PLI_BYTE8 *name)
|
vpi_printf("%*s Found %u extra argument%s.\n",
|
||||||
{
|
strlen(msg), " ", argc, argc == 1 ? "" : "s");
|
||||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
|
||||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
|
||||||
|
|
||||||
/* Check that there is an argument and that it is numeric. */
|
|
||||||
if (argv == 0) {
|
|
||||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
|
||||||
(int)vpi_get(vpiLineNo, callh));
|
|
||||||
vpi_printf("%s requires an argument.\n", name);
|
|
||||||
vpi_control(vpiFinish, 1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! is_numeric_obj(vpi_scan(argv))) {
|
|
||||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
|
||||||
(int)vpi_get(vpiLineNo, callh));
|
|
||||||
vpi_printf("%s's argument must be numeric.\n", name);
|
|
||||||
vpi_control(vpiFinish, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check that there is only a single argument. */
|
|
||||||
if (vpi_scan(argv) != 0) {
|
|
||||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
|
||||||
(int)vpi_get(vpiLineNo, callh));
|
|
||||||
vpi_printf("%s takes a single argument.\n", name);
|
|
||||||
vpi_control(vpiFinish, 1);
|
vpi_control(vpiFinish, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,9 +44,7 @@ extern const char*find_nexus_ident(int nex);
|
||||||
extern void set_nexus_ident(int nex, const char *id);
|
extern void set_nexus_ident(int nex, const char *id);
|
||||||
|
|
||||||
/* The compiletf routines are common for the VCD, LXT and LXT2 dumpers. */
|
/* The compiletf routines are common for the VCD, LXT and LXT2 dumpers. */
|
||||||
extern PLI_INT32 sys_no_arg_compiletf(PLI_BYTE8 *name);
|
|
||||||
extern PLI_INT32 sys_dumpfile_compiletf(PLI_BYTE8 *name);
|
extern PLI_INT32 sys_dumpfile_compiletf(PLI_BYTE8 *name);
|
||||||
extern PLI_INT32 sys_dumplimit_compiletf(PLI_BYTE8 *name);
|
|
||||||
extern PLI_INT32 sys_dumpvars_compiletf(PLI_BYTE8 *name);
|
extern PLI_INT32 sys_dumpvars_compiletf(PLI_BYTE8 *name);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -754,6 +754,47 @@ by the fork atomically joins that scope. Once the transient thread
|
||||||
joins the scope, it stays there until it ends. Threads never change
|
joins the scope, it stays there until it ends. Threads never change
|
||||||
scopes, not even transient threads.
|
scopes, not even transient threads.
|
||||||
|
|
||||||
|
VPI TASK/FUNCTION CALLS
|
||||||
|
|
||||||
|
Threads call vpi tasks with the %vpi_call or %vpi_func
|
||||||
|
instructions. The formats are:
|
||||||
|
|
||||||
|
%vpi_call <file-index> <lineno> <name>, <args>... ;
|
||||||
|
%vpi_func <file-index> <lineno> <name>, <args>... ;
|
||||||
|
%vpi_func/r <file-index> <lineno> <name>, <args>... ;
|
||||||
|
|
||||||
|
The <file-index> is an index into the string table. The indexed string
|
||||||
|
is the source code file name where this call appears. The <lineno> is
|
||||||
|
the line number from the source code where this task/function appears.
|
||||||
|
|
||||||
|
The <name> is a string that is the name of the system
|
||||||
|
task/function. For example, "$display", $strobe", etc. This name is
|
||||||
|
looked up and compared with the registered system tasks/functions.
|
||||||
|
|
||||||
|
The <args>... is a comma (",") separated list of arguments. These are
|
||||||
|
made available to the VPI code as vpi handles.
|
||||||
|
|
||||||
|
* The &A<> argument
|
||||||
|
|
||||||
|
The &A<> argument is a reference to the word of a variable array. The
|
||||||
|
syntax is:
|
||||||
|
|
||||||
|
&A '<' <symbol> , <number> '>'
|
||||||
|
|
||||||
|
The <symbol> is the label for a variable array, and the <number> is
|
||||||
|
the cannonical word index as an unsigned integer.
|
||||||
|
|
||||||
|
* The T<> argument
|
||||||
|
|
||||||
|
This is the catch-all for arguments that are not otherwise
|
||||||
|
handled. This references the bits directly in the thread. The format
|
||||||
|
is:
|
||||||
|
|
||||||
|
T '<' <base>, <wid>, <su> '>'
|
||||||
|
|
||||||
|
The <base> and <wid> are the base of a vector value in the thread and
|
||||||
|
the width of the vector. The <su> is 's' or 'u' for signed or unsigned.
|
||||||
|
|
||||||
TRUTH TABLES
|
TRUTH TABLES
|
||||||
|
|
||||||
The logic that a functor represents is expressed as a truth table. The
|
The logic that a functor represents is expressed as a truth table. The
|
||||||
|
|
|
||||||
153
vvp/array.cc
153
vvp/array.cc
|
|
@ -55,6 +55,8 @@ struct __vpiArray {
|
||||||
unsigned array_count;
|
unsigned array_count;
|
||||||
struct __vpiDecConst first_addr;
|
struct __vpiDecConst first_addr;
|
||||||
struct __vpiDecConst last_addr;
|
struct __vpiDecConst last_addr;
|
||||||
|
struct __vpiDecConst msb;
|
||||||
|
struct __vpiDecConst lsb;
|
||||||
// If this is a net array, nets lists the handles.
|
// If this is a net array, nets lists the handles.
|
||||||
vpiHandle*nets;
|
vpiHandle*nets;
|
||||||
// If this is a var array, then these are used instead of nets.
|
// If this is a var array, then these are used instead of nets.
|
||||||
|
|
@ -81,7 +83,25 @@ struct __vpiArrayIndex {
|
||||||
struct __vpiArrayVthrA {
|
struct __vpiArrayVthrA {
|
||||||
struct __vpiHandle base;
|
struct __vpiHandle base;
|
||||||
struct __vpiArray*array;
|
struct __vpiArray*array;
|
||||||
|
// If wid==0, then address is the address into the array.
|
||||||
unsigned address;
|
unsigned address;
|
||||||
|
// If wid >0, then the address is the base and wid the vector
|
||||||
|
// width of the index to pull from the thread.
|
||||||
|
unsigned wid;
|
||||||
|
|
||||||
|
unsigned get_address() const
|
||||||
|
{
|
||||||
|
if (wid == 0)
|
||||||
|
return address;
|
||||||
|
vvp_vector4_t tmp (wid);
|
||||||
|
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||||
|
vvp_bit4_t bit = vthread_get_bit(vpip_current_vthread, address+idx);
|
||||||
|
tmp.set_bit(idx, bit);
|
||||||
|
}
|
||||||
|
unsigned long val;
|
||||||
|
vector4_to_value(tmp, val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -121,8 +141,10 @@ static vpiHandle array_index_scan(vpiHandle ref, int);
|
||||||
static int array_index_free_object(vpiHandle ref);
|
static int array_index_free_object(vpiHandle ref);
|
||||||
|
|
||||||
static int vpi_array_var_word_get(int code, vpiHandle);
|
static int vpi_array_var_word_get(int code, vpiHandle);
|
||||||
|
static char*vpi_array_var_word_get_str(int code, vpiHandle);
|
||||||
static void vpi_array_var_word_get_value(vpiHandle, p_vpi_value);
|
static void vpi_array_var_word_get_value(vpiHandle, p_vpi_value);
|
||||||
static vpiHandle vpi_array_var_word_put_value(vpiHandle, p_vpi_value, int);
|
static vpiHandle vpi_array_var_word_put_value(vpiHandle, p_vpi_value, int);
|
||||||
|
static vpiHandle vpi_array_var_word_get_handle(int code, vpiHandle ref);
|
||||||
|
|
||||||
static int vpi_array_vthr_A_get(int code, vpiHandle);
|
static int vpi_array_vthr_A_get(int code, vpiHandle);
|
||||||
static char*vpi_array_vthr_A_get_str(int code, vpiHandle);
|
static char*vpi_array_vthr_A_get_str(int code, vpiHandle);
|
||||||
|
|
@ -171,10 +193,10 @@ static const struct __vpirt vpip_array_index_rt = {
|
||||||
static const struct __vpirt vpip_array_var_word_rt = {
|
static const struct __vpirt vpip_array_var_word_rt = {
|
||||||
vpiMemoryWord,
|
vpiMemoryWord,
|
||||||
&vpi_array_var_word_get,
|
&vpi_array_var_word_get,
|
||||||
0,
|
&vpi_array_var_word_get_str,
|
||||||
&vpi_array_var_word_get_value,
|
&vpi_array_var_word_get_value,
|
||||||
&vpi_array_var_word_put_value,
|
&vpi_array_var_word_put_value,
|
||||||
0,
|
&vpi_array_var_word_get_handle,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0
|
0
|
||||||
|
|
@ -342,11 +364,34 @@ static int vpi_array_var_word_get(int code, vpiHandle ref)
|
||||||
case vpiSize:
|
case vpiSize:
|
||||||
return (int) parent->vals_width;
|
return (int) parent->vals_width;
|
||||||
|
|
||||||
|
case vpiLeftRange:
|
||||||
|
return parent->msb.value;
|
||||||
|
|
||||||
|
case vpiRightRange:
|
||||||
|
return parent->lsb.value;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char*vpi_array_var_word_get_str(int code, vpiHandle ref)
|
||||||
|
{
|
||||||
|
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
|
||||||
|
struct __vpiArray*parent;
|
||||||
|
|
||||||
|
assert(obj);
|
||||||
|
unsigned index = decode_array_word_pointer(obj, parent);
|
||||||
|
|
||||||
|
if (code == vpiFile) { // Not implemented for now!
|
||||||
|
return simple_set_rbuf_str(file_names[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
char sidx [64];
|
||||||
|
snprintf(sidx, 63, "%d", (int)index + parent->first_addr.value);
|
||||||
|
return generic_get_str(code, &parent->scope->base, parent->name, sidx);
|
||||||
|
}
|
||||||
|
|
||||||
static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value value)
|
static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value value)
|
||||||
{
|
{
|
||||||
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
|
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
|
||||||
|
|
@ -377,6 +422,35 @@ static vpiHandle vpi_array_var_word_put_value(vpiHandle ref, p_vpi_value vp, int
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static vpiHandle vpi_array_var_word_get_handle(int code, vpiHandle ref)
|
||||||
|
{
|
||||||
|
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
|
||||||
|
struct __vpiArray*parent;
|
||||||
|
|
||||||
|
assert(obj);
|
||||||
|
decode_array_word_pointer(obj, parent);
|
||||||
|
|
||||||
|
switch (code) {
|
||||||
|
|
||||||
|
case vpiIndex:
|
||||||
|
break; // Not implemented!
|
||||||
|
|
||||||
|
case vpiLeftRange:
|
||||||
|
return &parent->msb.base;
|
||||||
|
|
||||||
|
case vpiRightRange:
|
||||||
|
return &parent->lsb.base;
|
||||||
|
|
||||||
|
case vpiParent:
|
||||||
|
return &parent->base;
|
||||||
|
|
||||||
|
case vpiScope:
|
||||||
|
return &parent->scope->base;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
# define ARRAY_ITERATOR(ref) (assert(ref->vpi_type->type_code==vpiIterator), \
|
# define ARRAY_ITERATOR(ref) (assert(ref->vpi_type->type_code==vpiIterator), \
|
||||||
(struct __vpiArrayIterator*)ref)
|
(struct __vpiArrayIterator*)ref)
|
||||||
|
|
||||||
|
|
@ -460,9 +534,14 @@ static int vpi_array_vthr_A_get(int code, vpiHandle ref)
|
||||||
return 0; // Not implemented for now!
|
return 0; // Not implemented for now!
|
||||||
|
|
||||||
case vpiSize:
|
case vpiSize:
|
||||||
assert(parent->vals);
|
|
||||||
return parent->vals_width;
|
return parent->vals_width;
|
||||||
|
|
||||||
|
case vpiLeftRange:
|
||||||
|
return parent->msb.value;
|
||||||
|
|
||||||
|
case vpiRightRange:
|
||||||
|
return parent->lsb.value;
|
||||||
|
|
||||||
// For now &A<> is only a constant select. This will need
|
// For now &A<> is only a constant select. This will need
|
||||||
// to be changed when it supports variable selection.
|
// to be changed when it supports variable selection.
|
||||||
case vpiConstantSelect:
|
case vpiConstantSelect:
|
||||||
|
|
@ -483,9 +562,9 @@ static char*vpi_array_vthr_A_get_str(int code, vpiHandle ref)
|
||||||
return simple_set_rbuf_str(file_names[0]);
|
return simple_set_rbuf_str(file_names[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
char index [64];
|
char sidx [64];
|
||||||
snprintf(index, 63, "%d", (int)obj->address + parent->first_addr.value);
|
snprintf(sidx, 63, "%d", (int)obj->get_address() + parent->first_addr.value);
|
||||||
return generic_get_str(code, &parent->scope->base, parent->name, index);
|
return generic_get_str(code, &parent->scope->base, parent->name, sidx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value value)
|
static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value value)
|
||||||
|
|
@ -495,18 +574,10 @@ static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value value)
|
||||||
struct __vpiArray*parent = obj->array;
|
struct __vpiArray*parent = obj->array;
|
||||||
|
|
||||||
assert(parent);
|
assert(parent);
|
||||||
assert(parent->vals);
|
|
||||||
assert(obj->address < parent->array_count);
|
|
||||||
|
|
||||||
unsigned index = obj->address;
|
unsigned index = obj->get_address();
|
||||||
unsigned width = parent->vals_width;
|
vvp_vector4_t tmp = array_get_word(parent, index);
|
||||||
|
vpip_vec4_get_value(tmp, parent->vals_width, false, value);
|
||||||
/* If we don't have a value yet just return X. */
|
|
||||||
if (parent->vals[index].size() == 0) {
|
|
||||||
vpip_vec4_get_value(vvp_vector4_t(width), width, false, value);
|
|
||||||
} else {
|
|
||||||
vpip_vec4_get_value(parent->vals[index], width, false, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int)
|
static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int)
|
||||||
|
|
@ -515,10 +586,10 @@ static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int)
|
||||||
assert(obj);
|
assert(obj);
|
||||||
struct __vpiArray*parent = obj->array;
|
struct __vpiArray*parent = obj->array;
|
||||||
|
|
||||||
unsigned index = obj->address;
|
unsigned index = obj->get_address();
|
||||||
|
|
||||||
assert(parent);
|
assert(parent);
|
||||||
assert(obj->address < parent->array_count);
|
assert(index < parent->array_count);
|
||||||
|
|
||||||
vvp_vector4_t val = vec4_from_vpi_value(vp, parent->vals_width);
|
vvp_vector4_t val = vec4_from_vpi_value(vp, parent->vals_width);
|
||||||
array_set_word(parent, index, 0, val);
|
array_set_word(parent, index, 0, val);
|
||||||
|
|
@ -534,6 +605,18 @@ static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref)
|
||||||
|
|
||||||
switch (code) {
|
switch (code) {
|
||||||
|
|
||||||
|
case vpiIndex:
|
||||||
|
break; // Not implemented!
|
||||||
|
|
||||||
|
case vpiLeftRange:
|
||||||
|
return &parent->msb.base;
|
||||||
|
|
||||||
|
case vpiRightRange:
|
||||||
|
return &parent->lsb.base;
|
||||||
|
|
||||||
|
case vpiParent:
|
||||||
|
return &parent->base;
|
||||||
|
|
||||||
case vpiScope:
|
case vpiScope:
|
||||||
return &parent->scope->base;
|
return &parent->scope->base;
|
||||||
}
|
}
|
||||||
|
|
@ -541,7 +624,6 @@ static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void array_set_word(vvp_array_t arr,
|
void array_set_word(vvp_array_t arr,
|
||||||
unsigned address,
|
unsigned address,
|
||||||
unsigned part_off,
|
unsigned part_off,
|
||||||
|
|
@ -646,6 +728,8 @@ static vpiHandle vpip_make_array(char*label, const char*name,
|
||||||
obj->nets = 0;
|
obj->nets = 0;
|
||||||
obj->vals = 0;
|
obj->vals = 0;
|
||||||
obj->vals_width = 0;
|
obj->vals_width = 0;
|
||||||
|
vpip_make_dec_const(&obj->msb, 0);
|
||||||
|
vpip_make_dec_const(&obj->lsb, 0);
|
||||||
obj->vals_words = 0;
|
obj->vals_words = 0;
|
||||||
|
|
||||||
// Initialize (clear) the read-ports list.
|
// Initialize (clear) the read-ports list.
|
||||||
|
|
@ -704,6 +788,8 @@ void compile_var_array(char*label, char*name, int last, int first,
|
||||||
/* Make the words. */
|
/* Make the words. */
|
||||||
arr->vals = new vvp_vector4_t[arr->array_count];
|
arr->vals = new vvp_vector4_t[arr->array_count];
|
||||||
arr->vals_width = labs(msb-lsb) + 1;
|
arr->vals_width = labs(msb-lsb) + 1;
|
||||||
|
vpip_make_dec_const(&arr->msb, msb);
|
||||||
|
vpip_make_dec_const(&arr->lsb, lsb);
|
||||||
|
|
||||||
free(label);
|
free(label);
|
||||||
free(name);
|
free(name);
|
||||||
|
|
@ -976,13 +1062,40 @@ vpiHandle vpip_make_vthr_A(char*label, unsigned addr)
|
||||||
|
|
||||||
obj->array = array_find(label);
|
obj->array = array_find(label);
|
||||||
assert(obj->array);
|
assert(obj->array);
|
||||||
|
free(label);
|
||||||
|
|
||||||
obj->address = addr;
|
obj->address = addr;
|
||||||
|
obj->wid = 0;
|
||||||
assert(addr < obj->array->array_count);
|
assert(addr < obj->array->array_count);
|
||||||
|
|
||||||
return &(obj->base);
|
return &(obj->base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vpiHandle vpip_make_vthr_A(char*label, char*symbol)
|
||||||
|
{
|
||||||
|
struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*)
|
||||||
|
malloc(sizeof (struct __vpiArrayVthrA));
|
||||||
|
|
||||||
|
obj->base.vpi_type = &vpip_array_vthr_A_rt;
|
||||||
|
|
||||||
|
obj->array = array_find(label);
|
||||||
|
assert(obj->array);
|
||||||
|
free(label);
|
||||||
|
|
||||||
|
unsigned base;
|
||||||
|
unsigned wid;
|
||||||
|
char sflag;
|
||||||
|
int rc = sscanf(symbol, "T<%u,%u,%c>", &base, &wid, &sflag);
|
||||||
|
assert(rc == 3);
|
||||||
|
free(symbol);
|
||||||
|
|
||||||
|
obj->address = base;
|
||||||
|
obj->wid = wid;
|
||||||
|
assert(sflag == 'u');
|
||||||
|
|
||||||
|
return &(obj->base);
|
||||||
|
}
|
||||||
|
|
||||||
void compile_array_cleanup(void)
|
void compile_array_cleanup(void)
|
||||||
{
|
{
|
||||||
if (array_table) {
|
if (array_table) {
|
||||||
|
|
|
||||||
|
|
@ -817,6 +817,8 @@ argument
|
||||||
}
|
}
|
||||||
| K_A '<' T_SYMBOL ',' T_NUMBER '>'
|
| K_A '<' T_SYMBOL ',' T_NUMBER '>'
|
||||||
{ $$ = vpip_make_vthr_A($3, $5); }
|
{ $$ = vpip_make_vthr_A($3, $5); }
|
||||||
|
| K_A '<' T_SYMBOL ',' T_SYMBOL '>'
|
||||||
|
{ $$ = vpip_make_vthr_A($3, $5); }
|
||||||
| K_PV '<' T_SYMBOL ',' T_NUMBER ',' T_NUMBER '>'
|
| K_PV '<' T_SYMBOL ',' T_NUMBER ',' T_NUMBER '>'
|
||||||
{ $$ = vpip_make_PV($3, $5, $7); }
|
{ $$ = vpip_make_PV($3, $5, $7); }
|
||||||
| K_PV '<' T_SYMBOL ',' '-' T_NUMBER ',' T_NUMBER '>'
|
| K_PV '<' T_SYMBOL ',' '-' T_NUMBER ',' T_NUMBER '>'
|
||||||
|
|
|
||||||
|
|
@ -446,6 +446,7 @@ vpiHandle vpip_make_vthr_vector(unsigned base, unsigned wid, bool signed_flag);
|
||||||
vpiHandle vpip_make_vthr_word(unsigned base, const char*type);
|
vpiHandle vpip_make_vthr_word(unsigned base, const char*type);
|
||||||
|
|
||||||
vpiHandle vpip_make_vthr_A(char*symbol, unsigned index);
|
vpiHandle vpip_make_vthr_A(char*symbol, unsigned index);
|
||||||
|
vpiHandle vpip_make_vthr_A(char*symbol, char*symbol);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function is called before any compilation to load VPI
|
* This function is called before any compilation to load VPI
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
# include <list>
|
# include <list>
|
||||||
# include <assert.h>
|
# include <assert.h>
|
||||||
# include <stdlib.h>
|
# include <stdlib.h>
|
||||||
|
# include <string.h>
|
||||||
#ifdef HAVE_MALLOC_H
|
#ifdef HAVE_MALLOC_H
|
||||||
# include <malloc.h>
|
# include <malloc.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue