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:
parent
bbdf622ea5
commit
04377151bc
69
PExpr.cc
69
PExpr.cc
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
||||||
20
PExpr.h
20
PExpr.h
|
|
@ -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,6 +597,8 @@ class PECallFunction : public PExpr {
|
||||||
|
|
||||||
virtual void dump(ostream &) const;
|
virtual void dump(ostream &) const;
|
||||||
|
|
||||||
|
virtual bool has_aa_term(Design*des, NetScope*scope) const;
|
||||||
|
|
||||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
|
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;
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
84
elaborate.cc
84
elaborate.cc
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue