Merge branch 'master' of ssh://steve-icarus@icarus.com/home/u/icarus/steve/git/verilog

This commit is contained in:
Stephen Williams 2008-06-09 16:58:21 -07:00
commit afa2478801
24 changed files with 665 additions and 337 deletions

17
PExpr.h
View File

@ -306,6 +306,11 @@ class PEIdent : public PExpr {
private:
// Common functions to calculate parts of part/bit selects.
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;
private:
@ -321,6 +326,18 @@ class PEIdent : public PExpr {
NetScope*found,
const NetExpr*par_msb,
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,
NetScope*scope,
NetNet*net,

View File

@ -882,6 +882,51 @@ bool PEIdent::calculate_up_do_width_(Design*des, NetScope*scope,
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 min, unsigned lval,
bool&unsized_flag) const
@ -1094,6 +1139,131 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
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
* 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_lsb) const
{
NetExpr*tmp = par->dup_expr();
const name_component_t&name_tail = path_.back();
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
if (!name_tail.index.empty())
use_sel = name_tail.index.back().sel;
if (use_sel == index_component_t::SEL_PART) {
ivl_assert(*this, !name_tail.index.empty());
const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.msb);
ivl_assert(*this, index_tail.lsb);
// NOTE TO SELF: This is the way I want to see this code
// structured. This closely follows the structure of the
// elaborate_expr_net_ code, which splits all the various
// selects to different methods.
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
it by pulling the right bits out and making a
sized unsigned constant. This code assumes the
lsb of a parameter is 0 and the msb is the
width of the parameter. */
if (use_sel == index_component_t::SEL_IDX_UP)
return elaborate_expr_param_idx_up_(des, scope, par, found_in,
par_msb, par_lsb);
verinum*lsn = index_tail.lsb->eval_const(des, scope);
verinum*msn = index_tail.msb->eval_const(des, scope);
if ((lsn == 0) || (msn == 0)) {
cerr << get_fileline() << ": error: "
"Part select expressions must be "
"constant expressions." << endl;
des->errors += 1;
return 0;
}
// NOTE TO SELF (continued): The code below should be
// rewritten in the above format, as I get to it.
long lsb = lsn->as_long();
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;
NetExpr*tmp = par->dup_expr();
NetEConst*le = dynamic_cast<NetEConst*>(tmp);
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) {
if (use_sel == index_component_t::SEL_IDX_DO) {
ivl_assert(*this, !name_tail.index.empty());
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
// of this expression is a 'bx vector the width of a word.
if (!net->array_index_is_valid(addr)) {
verinum xxx (verinum::Vx, net->vector_width());
NetEConst*resx = new NetEConst(xxx);
NetEConst*resx = make_const_x(net->vector_width());
resx->set_line(*this);
delete word_index;
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
unsigned. Remember that any order is possible,
i.e., [1:0], [-4:6], etc. */
unsigned long wid = 1 + ((msv>lsv)? (msv-lsv) : (lsv-msv));
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());
unsigned long wid = 1 + labs(msv-lsv);
if (net->sig()->sb_to_idx(msv) < net->sig()->sb_to_idx(lsv)) {
cerr << get_fileline() << ": error: part select ["
@ -1457,27 +1562,79 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
return net;
}
if (net->sig()->sb_to_idx(msv) >= (signed) net->vector_width()) {
cerr << get_fileline() << ": error: part select ["
<< msv << ":" << lsv << "] out of range." << endl;
des->errors += 1;
//delete lsn;
//delete msn;
return net;
}
long sb_lsb = net->sig()->sb_to_idx(lsv);
long sb_msb = net->sig()->sb_to_idx(msv);
// If the part select covers exactly the entire
// vector, then do not bother with it. Return the
// signal itself.
if (net->sig()->sb_to_idx(lsv) == 0 && wid == net->vector_width())
if (sb_lsb == 0 && wid == net->vector_width())
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);
ss->set_line(*this);
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;
}
/*
@ -1486,14 +1643,7 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
NetESignal*net, NetScope*found_in) 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*base = elab_and_eval(des, scope, index_tail.msb, -1);
NetExpr*base = calculate_up_do_base_(des, scope);
unsigned long wid = 0;
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
vector. This is legal, but returns a
constant 1'bx value. */
verinum x (verinum::Vx);
NetEConst*tmp = new NetEConst(x);
NetEConst*tmp = make_const_x(1);
tmp->set_line(*this);
cerr << get_fileline() << ": warning: Bit select ["

View File

@ -98,7 +98,16 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
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);
ivl_assert(*range->high_expr, tmp->high_expr);
} else {

View File

@ -123,6 +123,13 @@ NetExpr* make_sub_expr(long val, NetExpr*expr)
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)
{
if (expr->expr_width() == 1)

View File

@ -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_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
* a list of NetAssign_ objects. This function returns the width of

View File

@ -323,10 +323,15 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
%left K_POW
%left UNARY_PREC
/* to resolve dangling else ambiguity. */
%nonassoc less_than_K_else
%nonassoc K_else
/* to resolve exclude (... ambiguity */
%nonassoc '('
%nonassoc K_exclude
%%
/* A degenerate source file can be completely empty. */
@ -2432,7 +2437,8 @@ parameter_value_range
{ $$ = pform_parameter_value_range($1, true, $3, false, $5); }
| from_exclude '(' value_range_expression ':' value_range_expression ')'
{ $$ = 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

View File

@ -285,10 +285,17 @@ static void draw_vpi_taskfunc_args(const char*call_string,
word_ex = 0;
}
}
if (word_ex)
break;
snprintf(buffer, sizeof buffer, "&A<v%p, %u>", sig, use_word);
if (word_ex) {
struct vector_info av;
av = draw_eval_expr(word_ex, STUFF_OK_XZ);
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);
continue;
}

View File

@ -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
* and/or modify it in source code form under the terms of the GNU
@ -16,44 +16,11 @@
* along with this program; if not, write to the Free Software
* 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_user.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;
}
#include "vpi_config.h"
#include "vpi_user.h"
#include "sys_priv.h"
#include <string.h>
static PLI_INT32 sys_finish_calltf(PLI_BYTE8 *name)
{
@ -88,55 +55,16 @@ void sys_finish_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$finish";
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.user_data = (PLI_BYTE8*)"$finish";
tf_data.user_data = "$finish";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$stop";
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.user_data = (PLI_BYTE8*)"$stop";
tf_data.user_data = "$stop";
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.
*
*/

View File

@ -20,54 +20,13 @@
#include <vpi_user.h>
#include "sys_priv.h"
/*
* 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)
static PLI_INT32 finish_and_return_calltf(PLI_BYTE8* name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle arg;
s_vpi_value val;
(void) ud; /* Not used! */
(void) name; /* Not used! */
/* Get the return value. */
arg = vpi_scan(argv);
@ -92,9 +51,9 @@ void sys_special_register(void)
tf_data.type = vpiSysTask;
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.tfname = "$finish_and_return";
tf_data.user_data = 0;
tf_data.user_data = "$finish_and_return";
vpi_register_systf(&tf_data);
}

View File

@ -782,7 +782,7 @@ void sys_lxt_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumplimit";
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.user_data = "$dumplimit";
vpi_register_systf(&tf_data);

View File

@ -797,7 +797,7 @@ void sys_lxt2_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumplimit";
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.user_data = "$dumplimit";
vpi_register_systf(&tf_data);

View File

@ -18,6 +18,7 @@
*/
#include <assert.h>
#include <string.h>
#include "sys_priv.h"
PLI_UINT64 timerec_to_time64(const struct t_vpi_time*time)
@ -129,3 +130,108 @@ vpiHandle sys_func_module(vpiHandle 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;
}

View File

@ -50,4 +50,11 @@ extern unsigned is_string_obj(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

View File

@ -116,7 +116,7 @@ void sys_time_register()
tf_data.tfname = "$time";
tf_data.sysfunctype = vpiTimeFunc;
tf_data.calltf = sys_time_calltf;
tf_data.compiletf = 0;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$time";
vpi_register_systf(&tf_data);
@ -125,7 +125,7 @@ void sys_time_register()
tf_data.tfname = "$realtime";
tf_data.sysfunctype = vpiRealFunc;
tf_data.calltf = sys_realtime_calltf;
tf_data.compiletf = 0;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$realtime";
vpi_register_systf(&tf_data);
@ -134,7 +134,7 @@ void sys_time_register()
tf_data.tfname = "$stime";
tf_data.sysfunctype = vpiIntFunc;
tf_data.calltf = sys_time_calltf;
tf_data.compiletf = 0;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$stime";
vpi_register_systf(&tf_data);
@ -143,7 +143,7 @@ void sys_time_register()
tf_data.tfname = "$simtime";
tf_data.sysfunctype = vpiTimeFunc;
tf_data.calltf = sys_time_calltf;
tf_data.compiletf = 0;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$simtime";
vpi_register_systf(&tf_data);

View File

@ -795,7 +795,7 @@ void sys_vcd_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumplimit";
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.user_data = "$dumplimit";
vpi_register_systf(&tf_data);

View File

@ -85,7 +85,7 @@ void sys_vcdoff_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumplimit";
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.user_data = "$dumplimit";
vpi_register_systf(&tf_data);

View File

@ -34,7 +34,7 @@
/*
* 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);
assert(callh != 0);
@ -45,7 +45,7 @@ static PLI_INT32 simparam_compiletf(PLI_BYTE8* ud)
if (argv == 0) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, 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);
return 0;
}
@ -55,7 +55,8 @@ static PLI_INT32 simparam_compiletf(PLI_BYTE8* ud)
if (! is_string_obj(arg)) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, 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);
}
@ -64,12 +65,12 @@ static PLI_INT32 simparam_compiletf(PLI_BYTE8* ud)
if (arg == 0) return 0;
/* 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)) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
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);
}
/* 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),
(int)vpi_get(vpiLineNo, callh));
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);
}
}
/* We can only have two argument. */
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));
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);
}
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 argv = vpi_iterate(vpiArgument, callh);
@ -153,7 +163,8 @@ static PLI_INT32 simparam_calltf(PLI_BYTE8* ud)
if (! have_def_val) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, 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;
}
@ -168,7 +179,7 @@ static PLI_INT32 simparam_calltf(PLI_BYTE8* ud)
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 argv = vpi_iterate(vpiArgument, callh);
@ -217,7 +228,8 @@ static PLI_INT32 simparam_str_calltf(PLI_BYTE8* ud)
if (defval == 0) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, 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>");
}
retval = defval;
@ -234,9 +246,9 @@ static PLI_INT32 simparam_str_calltf(PLI_BYTE8* ud)
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!
}

View File

@ -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,
* 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. */
PLI_INT32 sys_dumpfile_compiletf(PLI_BYTE8 *name)
{
@ -217,7 +202,7 @@ PLI_INT32 sys_dumpfile_compiletf(PLI_BYTE8 *name)
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_printf("%s requires a single string argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
@ -228,44 +213,19 @@ PLI_INT32 sys_dumpfile_compiletf(PLI_BYTE8 *name)
vpi_control(vpiFinish, 1);
}
/* Check that there is only a single argument. */
/* Make sure there are no extra arguments. */
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));
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. */
PLI_INT32 sys_dumplimit_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 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_printf("%s %s takes a single string argument.\n", msg, name);
vpi_printf("%*s Found %u extra argument%s.\n",
strlen(msg), " ", argc, argc == 1 ? "" : "s");
vpi_control(vpiFinish, 1);
}

View File

@ -44,9 +44,7 @@ extern const char*find_nexus_ident(int nex);
extern void set_nexus_ident(int nex, const char *id);
/* 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_dumplimit_compiletf(PLI_BYTE8 *name);
extern PLI_INT32 sys_dumpvars_compiletf(PLI_BYTE8 *name);
#endif

View File

@ -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
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
The logic that a functor represents is expressed as a truth table. The

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2007-2008 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
* General Public License as published by the Free Software
@ -55,6 +55,8 @@ struct __vpiArray {
unsigned array_count;
struct __vpiDecConst first_addr;
struct __vpiDecConst last_addr;
struct __vpiDecConst msb;
struct __vpiDecConst lsb;
// If this is a net array, nets lists the handles.
vpiHandle*nets;
// If this is a var array, then these are used instead of nets.
@ -81,7 +83,25 @@ struct __vpiArrayIndex {
struct __vpiArrayVthrA {
struct __vpiHandle base;
struct __vpiArray*array;
// If wid==0, then address is the address into the array.
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 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 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 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 = {
vpiMemoryWord,
&vpi_array_var_word_get,
0,
&vpi_array_var_word_get_str,
&vpi_array_var_word_get_value,
&vpi_array_var_word_put_value,
0,
&vpi_array_var_word_get_handle,
0,
0,
0
@ -342,11 +364,34 @@ static int vpi_array_var_word_get(int code, vpiHandle ref)
case vpiSize:
return (int) parent->vals_width;
case vpiLeftRange:
return parent->msb.value;
case vpiRightRange:
return parent->lsb.value;
default:
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)
{
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;
}
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), \
(struct __vpiArrayIterator*)ref)
@ -460,9 +534,14 @@ static int vpi_array_vthr_A_get(int code, vpiHandle ref)
return 0; // Not implemented for now!
case vpiSize:
assert(parent->vals);
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
// to be changed when it supports variable selection.
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]);
}
char index [64];
snprintf(index, 63, "%d", (int)obj->address + parent->first_addr.value);
return generic_get_str(code, &parent->scope->base, parent->name, index);
char sidx [64];
snprintf(sidx, 63, "%d", (int)obj->get_address() + parent->first_addr.value);
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)
@ -495,18 +574,10 @@ static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value value)
struct __vpiArray*parent = obj->array;
assert(parent);
assert(parent->vals);
assert(obj->address < parent->array_count);
unsigned index = obj->address;
unsigned width = parent->vals_width;
/* 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);
}
unsigned index = obj->get_address();
vvp_vector4_t tmp = array_get_word(parent, index);
vpip_vec4_get_value(tmp, parent->vals_width, false, value);
}
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);
struct __vpiArray*parent = obj->array;
unsigned index = obj->address;
unsigned index = obj->get_address();
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);
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) {
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;
}
@ -541,7 +624,6 @@ static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref)
return 0;
}
void array_set_word(vvp_array_t arr,
unsigned address,
unsigned part_off,
@ -646,6 +728,8 @@ static vpiHandle vpip_make_array(char*label, const char*name,
obj->nets = 0;
obj->vals = 0;
obj->vals_width = 0;
vpip_make_dec_const(&obj->msb, 0);
vpip_make_dec_const(&obj->lsb, 0);
obj->vals_words = 0;
// 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. */
arr->vals = new vvp_vector4_t[arr->array_count];
arr->vals_width = labs(msb-lsb) + 1;
vpip_make_dec_const(&arr->msb, msb);
vpip_make_dec_const(&arr->lsb, lsb);
free(label);
free(name);
@ -976,13 +1062,40 @@ vpiHandle vpip_make_vthr_A(char*label, unsigned addr)
obj->array = array_find(label);
assert(obj->array);
free(label);
obj->address = addr;
obj->wid = 0;
assert(addr < obj->array->array_count);
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)
{
if (array_table) {

View File

@ -817,6 +817,8 @@ argument
}
| K_A '<' T_SYMBOL ',' T_NUMBER '>'
{ $$ = 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 '>'
{ $$ = vpip_make_PV($3, $5, $7); }
| K_PV '<' T_SYMBOL ',' '-' T_NUMBER ',' T_NUMBER '>'

View File

@ -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_A(char*symbol, unsigned index);
vpiHandle vpip_make_vthr_A(char*symbol, char*symbol);
/*
* This function is called before any compilation to load VPI

View File

@ -25,6 +25,7 @@
# include <list>
# include <assert.h>
# include <stdlib.h>
# include <string.h>
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif