Checks for illegal use of automatically allocated variables.

This patch adds a number of compile and run-time checks for illegal
uses of variables declared in automatic tasks and functions. It
also adds a check for event expressions in automatic tasks that use
features not yet supported in VVP.
This commit is contained in:
Martin Whitaker 2008-11-09 00:26:55 +00:00 committed by Stephen Williams
parent bbdf622ea5
commit 04377151bc
15 changed files with 283 additions and 43 deletions

View File

@ -24,6 +24,7 @@
# include "compiler.h" # include "compiler.h"
# include "PExpr.h" # include "PExpr.h"
# include "Module.h" # include "Module.h"
# include "netmisc.h"
# include <typeinfo> # include <typeinfo>
PExpr::PExpr() PExpr::PExpr()
@ -35,6 +36,11 @@ PExpr::~PExpr()
{ {
} }
bool PExpr::has_aa_term(Design*, NetScope*) const
{
return false;
}
bool PExpr::is_the_same(const PExpr*that) const bool PExpr::is_the_same(const PExpr*that) const
{ {
return typeid(this) == typeid(that); return typeid(this) == typeid(that);
@ -64,6 +70,12 @@ PEBinary::~PEBinary()
{ {
} }
bool PEBinary::has_aa_term(Design*des, NetScope*scope) const
{
assert(left_ && right_);
return left_->has_aa_term(des, scope) || right_->has_aa_term(des, scope);
}
PEBComp::PEBComp(char op, PExpr*l, PExpr*r) PEBComp::PEBComp(char op, PExpr*l, PExpr*r)
: PEBinary(op, l, r) : PEBinary(op, l, r)
{ {
@ -130,6 +142,15 @@ PECallFunction::~PECallFunction()
{ {
} }
bool PECallFunction::has_aa_term(Design*des, NetScope*scope) const
{
bool flag = false;
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
flag = parms_[idx]->has_aa_term(des, scope) || flag;
}
return flag;
}
PEConcat::PEConcat(const svector<PExpr*>&p, PExpr*r) PEConcat::PEConcat(const svector<PExpr*>&p, PExpr*r)
: parms_(p), repeat_(r) : parms_(p), repeat_(r)
{ {
@ -140,6 +161,18 @@ PEConcat::~PEConcat()
delete repeat_; delete repeat_;
} }
bool PEConcat::has_aa_term(Design*des, NetScope*scope) const
{
bool flag = false;
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
flag = parms_[idx]->has_aa_term(des, scope) || flag;
}
if (repeat_)
flag = repeat_->has_aa_term(des, scope) || flag;
return flag;
}
PEEvent::PEEvent(PEEvent::edge_t t, PExpr*e) PEEvent::PEEvent(PEEvent::edge_t t, PExpr*e)
: type_(t), expr_(e) : type_(t), expr_(e)
{ {
@ -154,6 +187,12 @@ PEEvent::edge_t PEEvent::type() const
return type_; return type_;
} }
bool PEEvent::has_aa_term(Design*des, NetScope*scope) const
{
assert(expr_);
return expr_->has_aa_term(des, scope);
}
PExpr* PEEvent::expr() const PExpr* PEEvent::expr() const
{ {
return expr_; return expr_;
@ -188,6 +227,22 @@ PEIdent::~PEIdent()
{ {
} }
bool PEIdent::has_aa_term(Design*des, NetScope*scope) const
{
NetNet* net = 0;
const NetExpr*par = 0;
NetEvent* eve = 0;
const NetExpr*ex1, *ex2;
scope = symbol_search(0, des, scope, path_, net, par, eve, ex1, ex2);
if (scope)
return scope->is_auto();
else
return false;
}
PENumber::PENumber(verinum*vp) PENumber::PENumber(verinum*vp)
: value_(vp) : value_(vp)
{ {
@ -237,6 +292,14 @@ PETernary::~PETernary()
{ {
} }
bool PETernary::has_aa_term(Design*des, NetScope*scope) const
{
assert(expr_ && tru_ && fal_);
return expr_->has_aa_term(des, scope)
|| tru_->has_aa_term(des, scope)
|| fal_->has_aa_term(des, scope);
}
PEUnary::PEUnary(char op, PExpr*ex) PEUnary::PEUnary(char op, PExpr*ex)
: op_(op), expr_(ex) : op_(op), expr_(ex)
{ {
@ -245,3 +308,9 @@ PEUnary::PEUnary(char op, PExpr*ex)
PEUnary::~PEUnary() PEUnary::~PEUnary()
{ {
} }
bool PEUnary::has_aa_term(Design*des, NetScope*scope) const
{
assert(expr_);
return expr_->has_aa_term(des, scope);
}

22
PExpr.h
View File

@ -46,6 +46,10 @@ class PExpr : public LineInfo {
virtual void dump(ostream&) const; virtual void dump(ostream&) const;
// This method tests whether the expression contains any
// references to automatically allocated variables.
virtual bool has_aa_term(Design*des, NetScope*scope) const;
// This method tests the width that the expression wants to // This method tests the width that the expression wants to
// be. It is used by elaboration of assignments to figure out // be. It is used by elaboration of assignments to figure out
// the width of the expression. // the width of the expression.
@ -156,6 +160,8 @@ class PEConcat : public PExpr {
virtual verinum* eval_const(Design*des, NetScope*sc) const; virtual verinum* eval_const(Design*des, NetScope*sc) const;
virtual void dump(ostream&) const; virtual void dump(ostream&) const;
virtual bool has_aa_term(Design*des, NetScope*scope) const;
virtual unsigned test_width(Design*des, NetScope*scope, virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval, unsigned min, unsigned lval,
ivl_variable_type_t&expr_type, ivl_variable_type_t&expr_type,
@ -200,6 +206,8 @@ class PEEvent : public PExpr {
virtual void dump(ostream&) const; virtual void dump(ostream&) const;
virtual bool has_aa_term(Design*des, NetScope*scope) const;
private: private:
edge_t type_; edge_t type_;
PExpr *expr_; PExpr *expr_;
@ -247,6 +255,9 @@ class PEIdent : public PExpr {
void append_name(perm_string); void append_name(perm_string);
virtual void dump(ostream&) const; virtual void dump(ostream&) const;
virtual bool has_aa_term(Design*des, NetScope*scope) const;
virtual unsigned test_width(Design*des, NetScope*scope, virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval, unsigned min, unsigned lval,
ivl_variable_type_t&expr_type, ivl_variable_type_t&expr_type,
@ -420,6 +431,8 @@ class PEUnary : public PExpr {
virtual void dump(ostream&out) const; virtual void dump(ostream&out) const;
virtual bool has_aa_term(Design*des, NetScope*scope) const;
virtual unsigned test_width(Design*des, NetScope*scope, virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval, unsigned min, unsigned lval,
ivl_variable_type_t&expr_type, ivl_variable_type_t&expr_type,
@ -448,6 +461,8 @@ class PEBinary : public PExpr {
virtual void dump(ostream&out) const; virtual void dump(ostream&out) const;
virtual bool has_aa_term(Design*des, NetScope*scope) const;
virtual unsigned test_width(Design*des, NetScope*scope, virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval, unsigned min, unsigned lval,
ivl_variable_type_t&expr_type, ivl_variable_type_t&expr_type,
@ -541,6 +556,9 @@ class PETernary : public PExpr {
~PETernary(); ~PETernary();
virtual void dump(ostream&out) const; virtual void dump(ostream&out) const;
virtual bool has_aa_term(Design*des, NetScope*scope) const;
virtual unsigned test_width(Design*des, NetScope*scope, virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval, unsigned min, unsigned lval,
ivl_variable_type_t&expr_type, ivl_variable_type_t&expr_type,
@ -579,7 +597,9 @@ class PECallFunction : public PExpr {
virtual void dump(ostream &) const; virtual void dump(ostream &) const;
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, virtual bool has_aa_term(Design*des, NetScope*scope) const;
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
int expr_wid, bool sys_task_arg) const; int expr_wid, bool sys_task_arg) const;
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const; virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;

View File

@ -228,6 +228,15 @@ void PEventStatement::set_statement(Statement*st)
statement_ = st; statement_ = st;
} }
bool PEventStatement::has_aa_term(Design*des, NetScope*scope)
{
bool flag = false;
for (unsigned idx = 0 ; idx < expr_.count() ; idx += 1) {
flag = expr_[idx]->has_aa_term(des, scope) || flag;
}
return flag;
}
PForce::PForce(PExpr*l, PExpr*r) PForce::PForce(PExpr*l, PExpr*r)
: lval_(l), expr_(r) : lval_(l), expr_(r)
{ {

View File

@ -347,6 +347,8 @@ class PEventStatement : public Statement {
virtual void elaborate_scope(Design*des, NetScope*scope) const; virtual void elaborate_scope(Design*des, NetScope*scope) const;
virtual void elaborate_sig(Design*des, NetScope*scope) const; virtual void elaborate_sig(Design*des, NetScope*scope) const;
bool has_aa_term(Design*des, NetScope*scope);
// This method is used to elaborate, but attach a previously // This method is used to elaborate, but attach a previously
// elaborated statement to the event. // elaborated statement to the event.
NetProc* elaborate_st(Design*des, NetScope*scope, NetProc*st) const; NetProc* elaborate_st(Design*des, NetScope*scope, NetProc*st) const;

View File

@ -1123,8 +1123,9 @@ void PBlock::elaborate_scope(Design*des, NetScope*scope) const
? NetScope::FORK_JOIN ? NetScope::FORK_JOIN
: NetScope::BEGIN_END); : NetScope::BEGIN_END);
my_scope->set_line(get_file(), get_lineno()); my_scope->set_line(get_file(), get_lineno());
my_scope->is_auto(scope->is_auto());
// Scan the parameters in the module, and create stub parameter // Scan the parameters in the scope, and create stub parameter
// entries in the scope for the parameter names. // entries in the scope for the parameter names.
collect_scope_parameters_(my_scope, parameters); collect_scope_parameters_(my_scope, parameters);

View File

@ -2012,6 +2012,14 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const
return 0; return 0;
} }
if (scope->is_auto() && lval()->has_aa_term(des, scope)) {
cerr << get_fileline() << ": error: automatically allocated "
"variables may not be assigned values using non-blocking "
"assignments." << endl;
des->errors += 1;
return 0;
}
/* Elaborate the l-value. */ /* Elaborate the l-value. */
NetAssign_*lv = elaborate_lval(des, scope); NetAssign_*lv = elaborate_lval(des, scope);
if (lv == 0) return 0; if (lv == 0) return 0;
@ -2042,6 +2050,15 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const
NetEvWait*event = 0; NetEvWait*event = 0;
if (count_ != 0 || event_ != 0) { if (count_ != 0 || event_ != 0) {
if (count_ != 0) { if (count_ != 0) {
if (scope->is_auto() && count_->has_aa_term(des, scope)) {
cerr << get_fileline() << ": error: automatically "
"allocated variables may not be referenced "
"in intra-assignment event controls of "
"non-blocking assignments." << endl;
des->errors += 1;
return 0;
}
assert(event_ != 0); assert(event_ != 0);
count = elab_and_eval(des, scope, count_, -1); count = elab_and_eval(des, scope, count_, -1);
if (count == 0) { if (count == 0) {
@ -2052,6 +2069,15 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const
} }
} }
if (scope->is_auto() && event_->has_aa_term(des, scope)) {
cerr << get_fileline() << ": error: automatically "
"allocated variables may not be referenced "
"in intra-assignment event controls of "
"non-blocking assignments." << endl;
des->errors += 1;
return 0;
}
NetProc*st = event_->elaborate(des, scope); NetProc*st = event_->elaborate(des, scope);
if (st == 0) { if (st == 0) {
cerr << get_fileline() << ": unable to elaborate " cerr << get_fileline() << ": unable to elaborate "
@ -2586,6 +2612,22 @@ NetCAssign* PCAssign::elaborate(Design*des, NetScope*scope) const
NetCAssign*dev = 0; NetCAssign*dev = 0;
assert(scope); assert(scope);
if (scope->is_auto() && lval_->has_aa_term(des, scope)) {
cerr << get_fileline() << ": error: automatically allocated "
"variables may not be assigned values using procedural "
"continuous assignments." << endl;
des->errors += 1;
return 0;
}
if (scope->is_auto() && expr_->has_aa_term(des, scope)) {
cerr << get_fileline() << ": error: automatically allocated "
"variables may not be referenced in procedural "
"continuous assignments." << endl;
des->errors += 1;
return 0;
}
NetAssign_*lval = lval_->elaborate_lval(des, scope, false); NetAssign_*lval = lval_->elaborate_lval(des, scope, false);
if (lval == 0) if (lval == 0)
return 0; return 0;
@ -2617,6 +2659,14 @@ NetDeassign* PDeassign::elaborate(Design*des, NetScope*scope) const
{ {
assert(scope); assert(scope);
if (scope->is_auto() && lval_->has_aa_term(des, scope)) {
cerr << get_fileline() << ": error: automatically allocated "
"variables may not be assigned values using procedural "
"continuous assignments." << endl;
des->errors += 1;
return 0;
}
NetAssign_*lval = lval_->elaborate_lval(des, scope, false); NetAssign_*lval = lval_->elaborate_lval(des, scope, false);
if (lval == 0) if (lval == 0)
return 0; return 0;
@ -2875,6 +2925,16 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope,
the sub-expression as a net and decide how to handle the sub-expression as a net and decide how to handle
the edge. */ the edge. */
if (scope->is_auto()) {
if (! dynamic_cast<PEIdent*>(expr_[idx]->expr())) {
cerr << get_fileline() << ": sorry, complex event "
"expressions are not yet supported in "
"automatic tasks." << endl;
des->errors += 1;
return 0;
}
}
bool save_flag = error_implicit; bool save_flag = error_implicit;
error_implicit = true; error_implicit = true;
NetExpr*tmp = elab_and_eval(des, scope, expr_[idx]->expr(), 0); NetExpr*tmp = elab_and_eval(des, scope, expr_[idx]->expr(), 0);
@ -3150,6 +3210,22 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const
NetForce*dev = 0; NetForce*dev = 0;
assert(scope); assert(scope);
if (scope->is_auto() && lval_->has_aa_term(des, scope)) {
cerr << get_fileline() << ": error: automatically allocated "
"variables may not be assigned values using procedural "
"force statements." << endl;
des->errors += 1;
return 0;
}
if (scope->is_auto() && expr_->has_aa_term(des, scope)) {
cerr << get_fileline() << ": error: automatically allocated "
"variables may not be referenced in procedural force "
"statements." << endl;
des->errors += 1;
return 0;
}
NetAssign_*lval = lval_->elaborate_lval(des, scope, true); NetAssign_*lval = lval_->elaborate_lval(des, scope, true);
if (lval == 0) if (lval == 0)
return 0; return 0;
@ -3355,6 +3431,14 @@ NetProc* PRelease::elaborate(Design*des, NetScope*scope) const
{ {
assert(scope); assert(scope);
if (scope->is_auto() && lval_->has_aa_term(des, scope)) {
cerr << get_fileline() << ": error: automatically allocated "
"variables may not be assigned values using procedural "
"force statements." << endl;
des->errors += 1;
return 0;
}
NetAssign_*lval = lval_->elaborate_lval(des, scope, true); NetAssign_*lval = lval_->elaborate_lval(des, scope, true);
if (lval == 0) if (lval == 0)
return 0; return 0;

View File

@ -100,7 +100,8 @@ static int vpi_get_dec_size(vpiHandle item)
); );
} }
static void array_from_iterator(struct strobe_cb_info*info, vpiHandle argv) static int array_from_iterator(struct strobe_cb_info*info, vpiHandle argv,
int check_no_aa_vars)
{ {
if (argv) { if (argv) {
vpiHandle item; vpiHandle item;
@ -111,13 +112,17 @@ static void array_from_iterator(struct strobe_cb_info*info, vpiHandle argv)
free(items); free(items);
info->nitems = 0; info->nitems = 0;
info->items = 0; info->items = 0;
return; return check_no_aa_vars;
} }
if (check_no_aa_vars && vpi_get(vpiAutomatic, items[0]))
check_no_aa_vars = 0;
for (item = vpi_scan(argv) ; item ; item = vpi_scan(argv)) { for (item = vpi_scan(argv) ; item ; item = vpi_scan(argv)) {
items = realloc(items, (nitems+1)*sizeof(vpiHandle)); items = realloc(items, (nitems+1)*sizeof(vpiHandle));
items[nitems] = item; items[nitems] = item;
nitems += 1; nitems += 1;
if (check_no_aa_vars && vpi_get(vpiAutomatic, item))
check_no_aa_vars = 0;
} }
info->nitems = nitems; info->nitems = nitems;
@ -127,6 +132,7 @@ static void array_from_iterator(struct strobe_cb_info*info, vpiHandle argv)
info->nitems = 0; info->nitems = 0;
info->items = 0; info->items = 0;
} }
return check_no_aa_vars;
} }
/* /*
@ -902,7 +908,7 @@ static PLI_INT32 sys_display_calltf(PLI_BYTE8*name)
info = malloc(sizeof (struct strobe_cb_info)); info = malloc(sizeof (struct strobe_cb_info));
info->default_format = get_default_format(name); info->default_format = get_default_format(name);
info->scope = scope; info->scope = scope;
array_from_iterator(info, argv); array_from_iterator(info, argv, 0);
vpi_put_userdata(sys, info); vpi_put_userdata(sys, info);
} }
@ -995,7 +1001,13 @@ static PLI_INT32 sys_strobe_calltf(PLI_BYTE8*name)
info->mcd = 1; info->mcd = 1;
} }
array_from_iterator(info, argv); if (!array_from_iterator(info, argv, 1)) {
vpi_printf("ERROR: %s parameters may not include automatically "
"allocated variables\n", name);
free(info->items);
free(info);
return 0;
}
info->name = strdup(name); info->name = strdup(name);
info->default_format = get_default_format(name); info->default_format = get_default_format(name);
info->scope= scope; info->scope= scope;
@ -1095,7 +1107,13 @@ static PLI_INT32 sys_monitor_calltf(PLI_BYTE8*name)
} }
/* Make an array of handles from the argument list. */ /* Make an array of handles from the argument list. */
array_from_iterator(&monitor_info, argv); if (!array_from_iterator(&monitor_info, argv, 1)) {
vpi_printf("ERROR: $monitor parameters may not include "
"automatically allocated variables\n");
free(monitor_info.items);
monitor_info.nitems = 0;
return 0;
}
monitor_info.name = strdup(name); monitor_info.name = strdup(name);
monitor_info.default_format = get_default_format(name); monitor_info.default_format = get_default_format(name);
monitor_info.scope = scope; monitor_info.scope = scope;
@ -1211,7 +1229,7 @@ static PLI_INT32 sys_fdisplay_calltf(PLI_BYTE8*name)
assert(scope); assert(scope);
info.default_format = get_default_format(name); info.default_format = get_default_format(name);
info.scope = scope; info.scope = scope;
array_from_iterator(&info, argv); array_from_iterator(&info, argv, 0);
do_display(mcd, &info); do_display(mcd, &info);
free(info.items); free(info.items);
@ -1969,7 +1987,7 @@ static PLI_INT32 sys_swrite_calltf(PLI_BYTE8 *name)
info.name = name; info.name = name;
info.default_format = get_default_format(name); info.default_format = get_default_format(name);
info.scope = scope; info.scope = scope;
array_from_iterator(&info, argv); array_from_iterator(&info, argv, 0);
/* Because %u and %z may put embedded NULL characters into the returned /* Because %u and %z may put embedded NULL characters into the returned
* string strlen() may not match the real size! */ * string strlen() may not match the real size! */
@ -2049,7 +2067,7 @@ static PLI_INT32 sys_sformat_calltf(PLI_BYTE8 *name)
info.name = name; info.name = name;
info.default_format = get_default_format(name); info.default_format = get_default_format(name);
info.scope = scope; info.scope = scope;
array_from_iterator(&info, argv); array_from_iterator(&info, argv, 0);
idx = -1; idx = -1;
size = get_format(&result, fmt, &info, &idx); size = get_format(&result, fmt, &info, &idx);
free(fmt); free(fmt);

View File

@ -454,6 +454,9 @@ static int vpi_array_var_word_get(int code, vpiHandle ref)
case vpiRightRange: case vpiRightRange:
return parent->lsb.value; return parent->lsb.value;
case vpiAutomatic:
return (int) parent->scope->is_automatic;
default: default:
return 0; return 0;
} }
@ -634,6 +637,9 @@ static int vpi_array_vthr_A_get(int code, vpiHandle ref)
case vpiRightRange: case vpiRightRange:
return parent->lsb.value; return parent->lsb.value;
case vpiAutomatic:
return (int) parent->scope->is_automatic;
// 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:

View File

@ -119,6 +119,14 @@ void delete_vpi_callback(struct __vpiCallback* ref)
*/ */
static struct __vpiCallback* make_value_change(p_cb_data data) static struct __vpiCallback* make_value_change(p_cb_data data)
{ {
if (vpi_get(vpiAutomatic, data->obj)) {
fprintf(stderr, "vpi error: cannot place value change "
"callback on automatically allocated "
"variable '%s'\n",
vpi_get_str(vpiName, data->obj));
return 0;
}
struct __vpiCallback*obj = new_vpi_callback(); struct __vpiCallback*obj = new_vpi_callback();
obj->cb_data = *data; obj->cb_data = *data;
if (data->time) { if (data->time) {

View File

@ -47,6 +47,9 @@ static int string_get(int code, vpiHandle ref)
case vpiConstType: case vpiConstType:
return vpiStringConst; return vpiStringConst;
case vpiAutomatic:
return 0;
default: default:
fprintf(stderr, "vvp error: get %d not supported " fprintf(stderr, "vvp error: get %d not supported "
"by vpiStringConst\n", code); "by vpiStringConst\n", code);
@ -343,6 +346,9 @@ static int binary_get(int code, vpiHandle ref)
case vpiSize: case vpiSize:
return rfp->bits.size(); return rfp->bits.size();
case vpiAutomatic:
return 0;
default: default:
fprintf(stderr, "vvp error: get %d not supported " fprintf(stderr, "vvp error: get %d not supported "
"by vpiBinaryConst\n", code); "by vpiBinaryConst\n", code);
@ -533,6 +539,9 @@ static int dec_get(int code, vpiHandle ref)
case vpiSize: case vpiSize:
return 32; return 32;
case vpiAutomatic:
return 0;
default: default:
fprintf(stderr, "vvp error: get %d not supported " fprintf(stderr, "vvp error: get %d not supported "
"by vpiDecConst\n", code); "by vpiDecConst\n", code);
@ -636,6 +645,9 @@ static int real_get(int code, vpiHandle ref)
case vpiSigned: case vpiSigned:
return 1; return 1;
case vpiAutomatic:
return 0;
default: default:
fprintf(stderr, "vvp error: get %d not supported " fprintf(stderr, "vvp error: get %d not supported "
"by vpiDecConst\n", code); "by vpiDecConst\n", code);

View File

@ -692,6 +692,14 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp,
if (flags!=vpiNoDelay && flags!=vpiForceFlag && flags!=vpiReleaseFlag) { if (flags!=vpiNoDelay && flags!=vpiForceFlag && flags!=vpiReleaseFlag) {
vvp_time64_t dly; vvp_time64_t dly;
if (vpi_get(vpiAutomatic, obj)) {
fprintf(stderr, "vpi error: cannot put a value with "
"a delay on automatically allocated "
"variable '%s'\n",
vpi_get_str(vpiName, obj));
return 0;
}
assert(when != 0); assert(when != 0);
switch (when->type) { switch (when->type) {

View File

@ -223,7 +223,6 @@ struct __vpiSignal {
unsigned signed_flag : 1; unsigned signed_flag : 1;
unsigned isint_ : 1; // original type was integer unsigned isint_ : 1; // original type was integer
unsigned is_netarray : 1; // This is word of a net array unsigned is_netarray : 1; // This is word of a net array
unsigned is_automatic : 1;
/* The represented value is here. */ /* The represented value is here. */
vvp_net_t*node; vvp_net_t*node;
}; };

View File

@ -75,6 +75,9 @@ static int scope_get(int code, vpiHandle obj)
case vpiTopModule: case vpiTopModule:
return 0x0 == ref->scope; return 0x0 == ref->scope;
case vpiAutomatic:
return (int) ref->is_automatic;
} }
return 0; return 0;
@ -330,33 +333,29 @@ compile_scope_decl(char*label, char*type, char*name, const char*tname,
struct __vpiScope*scope = new struct __vpiScope; struct __vpiScope*scope = new struct __vpiScope;
count_vpi_scopes += 1; count_vpi_scopes += 1;
if (strcmp(type,"module") == 0) { char*base_type = 0;
if (strncmp(type,"auto",4) == 0) {
scope->is_automatic = true;
base_type = &type[4];
} else {
scope->is_automatic = false;
base_type = &type[0];
}
if (strcmp(base_type,"module") == 0) {
scope->base.vpi_type = &vpip_scope_module_rt; scope->base.vpi_type = &vpip_scope_module_rt;
scope->is_automatic = false; } else if (strcmp(base_type,"function") == 0) {
} else if (strcmp(type,"autofunction") == 0) {
scope->base.vpi_type = &vpip_scope_function_rt; scope->base.vpi_type = &vpip_scope_function_rt;
scope->is_automatic = true; } else if (strcmp(base_type,"task") == 0) {
} else if (strcmp(type,"function") == 0) {
scope->base.vpi_type = &vpip_scope_function_rt;
scope->is_automatic = false;
} else if (strcmp(type,"autotask") == 0) {
scope->base.vpi_type = &vpip_scope_task_rt; scope->base.vpi_type = &vpip_scope_task_rt;
scope->is_automatic = true; } else if (strcmp(base_type,"fork") == 0) {
} else if (strcmp(type,"task") == 0) {
scope->base.vpi_type = &vpip_scope_task_rt;
scope->is_automatic = false;
} else if (strcmp(type,"fork") == 0) {
scope->base.vpi_type = &vpip_scope_fork_rt; scope->base.vpi_type = &vpip_scope_fork_rt;
scope->is_automatic = false; } else if (strcmp(base_type,"begin") == 0) {
} else if (strcmp(type,"begin") == 0) {
scope->base.vpi_type = &vpip_scope_begin_rt; scope->base.vpi_type = &vpip_scope_begin_rt;
scope->is_automatic = false; } else if (strcmp(base_type,"generate") == 0) {
} else if (strcmp(type,"generate") == 0) {
scope->base.vpi_type = &vpip_scope_begin_rt; scope->base.vpi_type = &vpip_scope_begin_rt;
scope->is_automatic = false;
} else { } else {
scope->base.vpi_type = &vpip_scope_module_rt; scope->base.vpi_type = &vpip_scope_module_rt;
scope->is_automatic = false;
assert(0); assert(0);
} }
@ -396,10 +395,6 @@ compile_scope_decl(char*label, char*type, char*name, const char*tname,
scope->time_units = sp->time_units; scope->time_units = sp->time_units;
scope->time_precision = sp->time_precision; scope->time_precision = sp->time_precision;
/* Scopes within automatic scopes are themselves automatic. */
if (sp->is_automatic)
scope->is_automatic = true;
} else { } else {
scope->scope = 0x0; scope->scope = 0x0;
@ -476,5 +471,3 @@ unsigned vpip_add_item_to_context(automatic_hooks_s*item,
/* Offset the context index by 2 to leave space for the list links. */ /* Offset the context index by 2 to leave space for the list links. */
return 2 + idx; return 2 + idx;
} }

View File

@ -528,10 +528,14 @@ static int signal_get(int code, vpiHandle ref)
else else
return 0; return 0;
case vpiLeftRange: return rfp->msb; case vpiLeftRange:
case vpiRightRange: return rfp->lsb; return rfp->msb;
case vpiAutomatic: return rfp->is_automatic; case vpiRightRange:
return rfp->lsb;
case vpiAutomatic:
return (int) vpip_scope(rfp)->is_automatic;
case _vpiNexusId: case _vpiNexusId:
if (rfp->msb == rfp->lsb) if (rfp->msb == rfp->lsb)
@ -863,7 +867,6 @@ vpiHandle vpip_make_int(const char*name, int msb, int lsb, vvp_net_t*vec)
struct __vpiSignal*rfp = (struct __vpiSignal*)obj; struct __vpiSignal*rfp = (struct __vpiSignal*)obj;
obj->vpi_type = &vpip_reg_rt; obj->vpi_type = &vpip_reg_rt;
rfp->isint_ = true; rfp->isint_ = true;
rfp->is_automatic = vpip_peek_current_scope()->is_automatic;
return obj; return obj;
} }
@ -876,7 +879,6 @@ vpiHandle vpip_make_reg(const char*name, int msb, int lsb,
vpiHandle obj = vpip_make_net(name, msb,lsb, signed_flag, vec); vpiHandle obj = vpip_make_net(name, msb,lsb, signed_flag, vec);
struct __vpiSignal*rfp = (struct __vpiSignal*)obj; struct __vpiSignal*rfp = (struct __vpiSignal*)obj;
obj->vpi_type = &vpip_reg_rt; obj->vpi_type = &vpip_reg_rt;
rfp->is_automatic = vpip_peek_current_scope()->is_automatic;
return obj; return obj;
} }
@ -915,7 +917,6 @@ vpiHandle vpip_make_net(const char*name, int msb, int lsb,
obj->signed_flag = signed_flag? 1 : 0; obj->signed_flag = signed_flag? 1 : 0;
obj->isint_ = 0; obj->isint_ = 0;
obj->is_netarray = 0; obj->is_netarray = 0;
obj->is_automatic = vpip_peek_current_scope()->is_automatic;
obj->node = node; obj->node = node;
// Place this object within a scope. If this object is // Place this object within a scope. If this object is
@ -972,11 +973,15 @@ static int PV_get(int code, vpiHandle ref)
case vpiConstantSelect: case vpiConstantSelect:
return rfp->twid == 0; return rfp->twid == 0;
case vpiLeftRange: rval += rfp->width; case vpiLeftRange:
rval += rfp->width;
case vpiRightRange: case vpiRightRange:
rval += vpi_get(vpiRightRange, rfp->parent) + PV_get_base(rfp); rval += vpi_get(vpiRightRange, rfp->parent) + PV_get_base(rfp);
return rval; return rval;
case vpiAutomatic:
return vpi_get(vpiAutomatic, rfp->parent);
default: default:
fprintf(stderr, "PV_get: property %d is unknown\n", code); fprintf(stderr, "PV_get: property %d is unknown\n", code);
} }

View File

@ -93,6 +93,9 @@ static int timevar_time_get(int code, vpiHandle ref)
case vpiFuncType: case vpiFuncType:
return vpiTimeFunc; return vpiTimeFunc;
case vpiAutomatic:
return 0;
default: default:
fprintf(stderr, "Code: %d\n", code); fprintf(stderr, "Code: %d\n", code);
assert(0); assert(0);
@ -148,6 +151,9 @@ static int timevar_realtime_get(int code, vpiHandle ref)
case vpiFuncType: case vpiFuncType:
return vpiRealFunc; return vpiRealFunc;
case vpiAutomatic:
return 0;
default: default:
fprintf(stderr, "Code: %d\n", code); fprintf(stderr, "Code: %d\n", code);
assert(0); assert(0);