diff --git a/PExpr.cc b/PExpr.cc index 3db0af799..614ff34b8 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -24,6 +24,7 @@ # include "compiler.h" # include "PExpr.h" # include "Module.h" +# include "netmisc.h" # include 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 { 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) : 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&p, PExpr*r) : parms_(p), repeat_(r) { @@ -140,6 +161,18 @@ PEConcat::~PEConcat() 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) : type_(t), expr_(e) { @@ -154,6 +187,12 @@ PEEvent::edge_t PEEvent::type() const 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 { 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) : 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) : op_(op), expr_(ex) { @@ -245,3 +308,9 @@ PEUnary::PEUnary(char op, PExpr*ex) PEUnary::~PEUnary() { } + +bool PEUnary::has_aa_term(Design*des, NetScope*scope) const +{ + assert(expr_); + return expr_->has_aa_term(des, scope); +} diff --git a/PExpr.h b/PExpr.h index b681f3cd2..8be86fcb0 100644 --- a/PExpr.h +++ b/PExpr.h @@ -46,6 +46,10 @@ class PExpr : public LineInfo { 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 // be. It is used by elaboration of assignments to figure out // the width of the expression. @@ -156,6 +160,8 @@ class PEConcat : public PExpr { virtual verinum* eval_const(Design*des, NetScope*sc) const; virtual void dump(ostream&) const; + virtual bool has_aa_term(Design*des, NetScope*scope) const; + virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, @@ -200,6 +206,8 @@ class PEEvent : public PExpr { virtual void dump(ostream&) const; + virtual bool has_aa_term(Design*des, NetScope*scope) const; + private: edge_t type_; PExpr *expr_; @@ -247,6 +255,9 @@ class PEIdent : public PExpr { void append_name(perm_string); virtual void dump(ostream&) const; + + virtual bool has_aa_term(Design*des, NetScope*scope) const; + virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, @@ -420,6 +431,8 @@ class PEUnary : public PExpr { virtual void dump(ostream&out) const; + virtual bool has_aa_term(Design*des, NetScope*scope) const; + virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, @@ -448,6 +461,8 @@ class PEBinary : public PExpr { virtual void dump(ostream&out) const; + virtual bool has_aa_term(Design*des, NetScope*scope) const; + virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, @@ -541,6 +556,9 @@ class PETernary : public PExpr { ~PETernary(); virtual void dump(ostream&out) const; + + virtual bool has_aa_term(Design*des, NetScope*scope) const; + virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, @@ -579,7 +597,9 @@ class PECallFunction : public PExpr { 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; virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const; diff --git a/PGenerate.h b/PGenerate.h index a9af52120..74082a27a 100644 --- a/PGenerate.h +++ b/PGenerate.h @@ -65,7 +65,7 @@ class PGenerate : public LineInfo, public LexicalScope { PScope*lexical_scope; enum scheme_t {GS_NONE, GS_LOOP, GS_CONDIT, GS_ELSE, - GS_CASE, GS_CASE_ITEM}; + GS_CASE, GS_CASE_ITEM, GS_NBLOCK}; scheme_t scheme_type; // generate loops have an index variable and three @@ -102,6 +102,7 @@ class PGenerate : public LineInfo, public LexicalScope { bool generate_scope_loop_(Design*des, NetScope*container); bool generate_scope_condit_(Design*des, NetScope*container, bool else_flag); bool generate_scope_case_(Design*des, NetScope*container); + bool generate_scope_nblock_(Design*des, NetScope*container); // Elaborate_scope within a generated scope. void elaborate_subscope_(Design*des, NetScope*scope); diff --git a/Statement.cc b/Statement.cc index d21adc1d1..517656a83 100644 --- a/Statement.cc +++ b/Statement.cc @@ -228,6 +228,15 @@ void PEventStatement::set_statement(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) : lval_(l), expr_(r) { diff --git a/Statement.h b/Statement.h index e99833131..30d8a60b4 100644 --- a/Statement.h +++ b/Statement.h @@ -347,6 +347,8 @@ class PEventStatement : public Statement { virtual void elaborate_scope(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 // elaborated statement to the event. NetProc* elaborate_st(Design*des, NetScope*scope, NetProc*st) const; diff --git a/elab_expr.cc b/elab_expr.cc index a129ef5d0..3bf2f3213 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -786,20 +786,26 @@ NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope, left_width = left_->test_width(des, scope, 0, 0, left_type, unsized_flag); /* Width of operands is self-determined. */ - int use_wid = left_width; - if (right_width > left_width) - use_wid = right_width; + + int use_wid_l = left_width; + if (type_is_vectorable(left_type) && (right_width > left_width)) + use_wid_l = right_width; + + int use_wid_r = right_width; + if (type_is_vectorable(right_type) && (left_width > right_width)) + use_wid_r = left_width; if (debug_elaborate) { cerr << get_fileline() << ": debug: " << "Comparison expression operands are " << left_width << " bits and " << right_width << " bits. Resorting to " - << use_wid << " bits." << endl; + << use_wid_l << " bits and " + << use_wid_r << " bits." << endl; } - NetExpr*lp = left_->elaborate_expr(des, scope, use_wid, false); - NetExpr*rp = right_->elaborate_expr(des, scope, use_wid, false); + NetExpr*lp = left_->elaborate_expr(des, scope, use_wid_l, false); + NetExpr*rp = right_->elaborate_expr(des, scope, use_wid_r, false); if ((lp == 0) || (rp == 0)) { delete lp; delete rp; @@ -812,12 +818,12 @@ NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope, // pad the width here. This matters because if the arguments // are signed, then this padding will do sign extension. if (type_is_vectorable(lp->expr_type())) - lp = pad_to_width(lp, use_wid); + lp = pad_to_width(lp, use_wid_l); if (type_is_vectorable(rp->expr_type())) - rp = pad_to_width(rp, use_wid); + rp = pad_to_width(rp, use_wid_r); - eval_expr(lp, use_wid); - eval_expr(rp, use_wid); + eval_expr(lp, use_wid_l); + eval_expr(rp, use_wid_r); // Handle some operand-specific special cases... switch (op_) { @@ -1413,12 +1419,26 @@ unsigned PEConcat::test_width(Design*des, NetScope*scope, { expr_type_ = IVL_VT_LOGIC; - if (debug_elaborate) - cerr << get_fileline() << ": debug: CONCAT MISSING TEST_WIDTH!" << endl; + unsigned count_width = 0; + for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) + count_width += parms_[idx]->test_width(des, scope, 0, 0, expr_type__, unsized_flag); + + if (repeat_) { + // The repeat expression is self-determined and its own type. + ivl_variable_type_t tmp_type = IVL_VT_NO_TYPE; + bool tmp_flag = false; + repeat_->test_width(des, scope, 0, 0, tmp_type, tmp_flag); + + count_width = 0; + if (debug_elaborate) + cerr << get_fileline() << ": debug: " + << "CONCAT MISSING TEST_WIDTH WHEN REPEAT IS PRESENT!" + << endl; + } expr_type__ = expr_type_; unsized_flag = false; - return 0; + return count_width; } // Keep track of the concatenation/repeat depth. diff --git a/elab_scope.cc b/elab_scope.cc index 1adf85402..2fcc1017b 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -461,7 +461,9 @@ bool PGenerate::generate_scope(Design*des, NetScope*container) case GS_CASE: return generate_scope_case_(des, container); - return true; + + case GS_NBLOCK: + return generate_scope_nblock_(des, container); case GS_CASE_ITEM: cerr << get_fileline() << ": internal error: " @@ -718,6 +720,29 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container) return true; } +bool PGenerate::generate_scope_nblock_(Design*des, NetScope*container) +{ + hname_t use_name (scope_name); + if (container->child(use_name)) { + cerr << get_fileline() << ": error: block/scope name " + << scope_name << " already used in this context." + << endl; + des->errors += 1; + return false; + } + if (debug_scopes) + cerr << get_fileline() << ": debug: Generate named block " + << ": Generate scope=" << use_name << endl; + + NetScope*scope = new NetScope(container, use_name, + NetScope::GENBLOCK); + scope->set_line(get_file(), get_lineno()); + + elaborate_subscope_(des, scope); + + return true; +} + void PGenerate::elaborate_subscope_(Design*des, NetScope*scope) { // Scan the generated scope for nested generate schemes, @@ -1123,8 +1148,9 @@ void PBlock::elaborate_scope(Design*des, NetScope*scope) const ? NetScope::FORK_JOIN : NetScope::BEGIN_END); 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. collect_scope_parameters_(my_scope, parameters); diff --git a/elaborate.cc b/elaborate.cc index 6a36b5065..8c5b47c9e 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -969,7 +969,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const // This is the array of pin expressions, shuffled to match the // order of the declaration. If the source instantiation uses - // bind by order, this is the same as the source list.Otherwise, + // bind by order, this is the same as the source list. Otherwise, // the source list is rearranged by name binding into this list. svectorpins (rmod->port_count()); @@ -1051,10 +1051,13 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const // later. NetScope::scope_vec_t&instance = scope->instance_arrays[get_name()]; + if (debug_elaborate) cerr << get_fileline() << ": debug: start " + "recursive elaboration of " << instance.size() << " instance(s) of " << + get_name() << "..." << endl; for (unsigned inst = 0 ; inst < instance.size() ; inst += 1) { rmod->elaborate(des, instance[inst]); } - + if (debug_elaborate) cerr << get_fileline() << ": debug: ...done." << endl; // Now connect the ports of the newly elaborated designs to @@ -1110,7 +1113,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const if (debug_elaborate) { cerr << get_fileline() << ": debug: " << get_name() - << ": Port " << idx << " has " << prts.size() + << ": Port " << (idx+1) << " has " << prts.size() << " sub-ports." << endl; } @@ -1427,7 +1430,7 @@ v NOTE that this also handles the case that the << " bits across all " << prts_vector_width/instance.size() << " input sub-ports of port " - << idx << "." << endl; + << (idx+1) << "." << endl; } for (unsigned ldx = 0 ; ldx < prts.size() ; ldx += 1) { @@ -1440,11 +1443,23 @@ v NOTE that this also handles the case that the spin += sp->vector_width(); } break; + case NetNet::PINOUT: - cerr << get_fileline() << ": XXXX: " - << "Forgot how to bind inout ports!" << endl; - des->errors += 1; + for (unsigned ldx = 0 ; ldx < prts.size() ; ldx += 1) { + NetNet*sp = prts[prts.size()-ldx-1]; + NetTran*ttmp = new NetTran(scope, + scope->local_symbol(), + sig->vector_width(), + sp->vector_width(), + spin); + des->add_node(ttmp); + ttmp->set_line(*this); + connect(ttmp->pin(0), sig->pin(0)); + connect(ttmp->pin(1), sp->pin(0)); + spin += sp->vector_width(); + } break; + case NetNet::PIMPLICIT: cerr << get_fileline() << ": internal error: " << "Unexpected IMPLICIT port" << endl; @@ -2012,17 +2027,26 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const 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. */ NetAssign_*lv = elaborate_lval(des, scope); if (lv == 0) return 0; NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv), lv->expr_type()); + if (rv == 0) return 0; /* Handle the (common) case that the r-value is a vector. This includes just about everything but reals. In this case, we need to pad the r-value to match the width of the l-value. - If in this case the l-val is a variable (i.e. real) then + If in this case the l-val is a variable (i.e., real) then the width to pad to will be 0, so this code is harmless. */ if (rv->expr_type() == IVL_VT_REAL) { @@ -2042,6 +2066,15 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const NetEvWait*event = 0; if (count_ != 0 || event_ != 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); count = elab_and_eval(des, scope, count_, -1); if (count == 0) { @@ -2052,6 +2085,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); if (st == 0) { cerr << get_fileline() << ": unable to elaborate " @@ -2586,6 +2628,22 @@ NetCAssign* PCAssign::elaborate(Design*des, NetScope*scope) const NetCAssign*dev = 0; 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); if (lval == 0) return 0; @@ -2617,6 +2675,14 @@ NetDeassign* PDeassign::elaborate(Design*des, NetScope*scope) const { 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); if (lval == 0) return 0; @@ -2875,6 +2941,16 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope, the sub-expression as a net and decide how to handle the edge. */ + if (scope->is_auto()) { + if (! dynamic_cast(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; error_implicit = true; NetExpr*tmp = elab_and_eval(des, scope, expr_[idx]->expr(), 0); @@ -3150,6 +3226,22 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const NetForce*dev = 0; 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); if (lval == 0) return 0; @@ -3355,6 +3447,14 @@ NetProc* PRelease::elaborate(Design*des, NetScope*scope) const { 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); if (lval == 0) return 0; diff --git a/eval_tree.cc b/eval_tree.cc index 40cdf517a..07b337970 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -133,7 +133,18 @@ NetExpr* NetEBAdd::eval_tree(int prune_to_width) verinum lval = lc->value(); verinum rval = rc->value(); - ivl_assert(*this, se->expr_width() == this->expr_width()); + if (lval.len() < expr_width()) + lval = pad_to_width(lval, expr_width()); + if (rval.len() < expr_width()) + rval = pad_to_width(rval, expr_width()); + + if (se->expr_width() > this->expr_width()) { + cerr << get_fileline() << ": internal error: " + << "expr_width()=" << expr_width() + << ", sub expr_width()=" << se->expr_width() + << ", sub expression=" << *se << endl; + } + ivl_assert(*this, se->expr_width() <= this->expr_width()); verinum val; if (op_ == se->op_) { @@ -146,7 +157,9 @@ NetExpr* NetEBAdd::eval_tree(int prune_to_width) val = rval - lval; } - val = pad_to_width(val, expr_width()); + // Since we padded the operands above to be the minimum + // width, the val should also be at least expr_width(). + ivl_assert(*this, val.len() >= expr_width()); if (val.len() > expr_width()) { verinum tmp (val, expr_width()); tmp.has_sign(val.has_sign()); diff --git a/parse.y b/parse.y index 6ea228b8c..1a0f29bd6 100644 --- a/parse.y +++ b/parse.y @@ -2235,6 +2235,16 @@ module_item cerr << @2 << ": warning: Anachronistic use of begin/end to surround generate schemes." << endl; } } + | K_generate K_begin ':' IDENTIFIER { + pform_start_generate_nblock(@1, $4); + } module_item_list_opt K_end K_endgenerate + { /* Detect and warn about anachronistic named begin/end use */ + if (generation_flag > GN_VER2001) { + warn_count += 1; + cerr << @2 << ": warning: Anachronistic use of named begin/end to surround generate schemes." << endl; + } + pform_endgenerate(); + } /* specify blocks are parsed but ignored. */ diff --git a/pform.cc b/pform.cc index 814e8aa8d..ef3ceacd4 100644 --- a/pform.cc +++ b/pform.cc @@ -530,6 +530,28 @@ void pform_start_generate_case(const struct vlltype&li, PExpr*expr) pform_cur_generate->loop_step = 0; } +/* + * The named block generate case. + */ +void pform_start_generate_nblock(const struct vlltype&li, char*name) +{ + PGenerate*gen = new PGenerate(scope_generate_counter++); + + FILE_NAME(gen, li); + + gen->parent = pform_cur_generate; + pform_cur_generate = gen; + + pform_cur_generate->scheme_type = PGenerate::GS_NBLOCK; + + pform_cur_generate->loop_init = 0; + pform_cur_generate->loop_test = 0; + pform_cur_generate->loop_step = 0; + + pform_cur_generate->scope_name = lex_strings.make(name); + delete[]name; +} + /* * The generate case item is a special case schema that takes its id * from the case schema that it is a part of. The idea is that the diff --git a/pform.h b/pform.h index a4a3f7fb2..553fa650b 100644 --- a/pform.h +++ b/pform.h @@ -204,6 +204,7 @@ extern void pform_start_generate_for(const struct vlltype&li, extern void pform_start_generate_if(const struct vlltype&li, PExpr*test); extern void pform_start_generate_else(const struct vlltype&li); extern void pform_start_generate_case(const struct vlltype&lp, PExpr*test); +extern void pform_start_generate_nblock(const struct vlltype&lp, char*name); extern void pform_generate_case_item(const struct vlltype&lp, PExpr*test); extern void pform_generate_block_name(char*name); extern void pform_endgenerate(); diff --git a/pform_dump.cc b/pform_dump.cc index f745567fe..e65a7c7bc 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -1002,6 +1002,8 @@ void PGenerate::dump(ostream&out, unsigned indent) const else out << " default:"; break; + case GS_NBLOCK: + out << " begin"; } if (scope_name) @@ -1035,7 +1037,11 @@ void PGenerate::dump(ostream&out, unsigned indent) const (*idx)->dump(out, indent+2); } - out << setw(indent) << "" << "endgenerate" << endl; + if (scheme_type == GS_NBLOCK) { + out << setw(indent) << "" << "end endgenerate" << endl; + } else { + out << setw(indent) << "" << "endgenerate" << endl; + } } void LexicalScope::dump_parameters_(ostream&out, unsigned indent) const diff --git a/symbol_search.cc b/symbol_search.cc index 0355fb6bb..8a50ae1c6 100644 --- a/symbol_search.cc +++ b/symbol_search.cc @@ -59,7 +59,7 @@ NetScope*symbol_search(const LineInfo*li, Design*des, NetScope*scope, scope = des->find_scope(scope, path_list); - if (scope->is_auto() && li) { + if (scope && scope->is_auto() && li) { cerr << li->get_fileline() << ": error: Hierarchical " "reference to automatically allocated item " "`" << key << "' in path `" << path << "'" << endl; diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 0bf7d7991..5ac0073b5 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -446,22 +446,31 @@ static vhdl_expr *translate_binary(ivl_expr_t e) static vhdl_expr *translate_select(ivl_expr_t e) { - vhdl_var_ref *from = - dynamic_cast(translate_expr(ivl_expr_oper1(e))); - if (NULL == from) { - error("Can only select from variable reference"); + vhdl_expr *from = translate_expr(ivl_expr_oper1(e)); + if (NULL == from) return NULL; - } ivl_expr_t o2 = ivl_expr_oper2(e); - if (o2) { + if (o2) { vhdl_expr *base = translate_expr(ivl_expr_oper2(e)); if (NULL == base) return NULL; - vhdl_type integer(VHDL_TYPE_INTEGER); - from->set_slice(base->cast(&integer), ivl_expr_width(e) - 1); - return from; + vhdl_var_ref *from_var_ref = dynamic_cast(from); + if (NULL == from_var_ref) { + // We can't directly select bits from something that's not + // a variable reference in VHDL, but we can emulate the + // effect with a shift and a resize + return new vhdl_binop_expr(from, VHDL_BINOP_SR, base->to_integer(), + new vhdl_type(*from->get_type())); + } + else { + // We can use the more idomatic VHDL slice notation on a + // single variable reference + vhdl_type integer(VHDL_TYPE_INTEGER); + from_var_ref->set_slice(base->cast(&integer), ivl_expr_width(e) - 1); + return from_var_ref; + } } else return from->resize(ivl_expr_width(e)); @@ -631,7 +640,7 @@ vhdl_expr *translate_expr(ivl_expr_t e) { assert(e); ivl_expr_type_t type = ivl_expr_type(e); - + switch (type) { case IVL_EX_STRING: return translate_string(e); diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 2d4272049..179abfbc9 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -275,12 +275,25 @@ static string make_safe_name(ivl_signal_t sig) const char *base = ivl_signal_basename(sig); if (base[0] == '_') return string("VL") + base; - + + // This is the complete list of VHDL reserved words const char *vhdl_reserved[] = { - "in", "out", "entity", "architecture", "inout", "array", - "is", "not", "and", "or", "bus", "bit", "line", // Etc... + "abs", "access", "after", "alias", "all", "and", "architecture", + "array", "assert", "attribute", "begin", "block", "body", "buffer", + "bus", "case", "component", "configuration", "constant", "disconnect", + "downto", "else", "elsif", "end", "entity", "exit", "file", "for", + "function", "generate", "generic", "group", "guarded", "if", "impure", + "in", "inertial", "inout", "is", "label", "library", "linkage", + "literal", "loop", "map", "mod", "nand", "new", "next", "nor", "not", + "null", "of", "on", "open", "or", "others", "out", "package", "port", + "postponed", "procedure", "process", "pure", "range", "record", "register", + "reject", "rem", "report", "return", "rol", "ror", "select", "severity", + "signal", "shared", "sla", "sll", "sra", "srl", "subtype", "then", "to", + "transport", "type", "unaffected", "units", "until", "use", "variable", + "wait", "when", "while", "with", "xnor", "xor", NULL }; + for (const char **p = vhdl_reserved; *p != NULL; p++) { if (strcasecmp(*p, base) == 0) { return string("VL_") + base; diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index aeb77ce60..b25827f02 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -1053,7 +1053,7 @@ static struct vector_info draw_binary_expr_lrs(ivl_expr_t exp, unsigned wid) /* shifting 0 gets 0. */ if (lv.base == 0) - break; + return lv; if (lv.base < 4) { struct vector_info tmp; @@ -1088,7 +1088,7 @@ static struct vector_info draw_binary_expr_lrs(ivl_expr_t exp, unsigned wid) /* shifting 0 gets 0. */ if (lv.base == 0) - break; + return lv; if (lv.base < 4) { struct vector_info tmp; @@ -1123,12 +1123,12 @@ static struct vector_info draw_binary_expr_lrs(ivl_expr_t exp, unsigned wid) /* shifting 0 gets 0. */ if (lv.base == 0) - break; + return lv; /* Sign extend any constant begets itself, if this expression is signed. */ if ((lv.base < 4) && (ivl_expr_signed(exp))) - break; + return lv; if (lv.base < 4) { struct vector_info tmp; @@ -1823,6 +1823,8 @@ static struct vector_info draw_pad_expr(ivl_expr_t exp, unsigned wid) fprintf(vvp_out, " %%mov %u, 0, %u;\n", res.base+subv.wid, res.wid - subv.wid); } + if (subv.base >= 8) + clr_vector(subv); save_expression_lookaside(res.base, exp, wid); return res; diff --git a/vpi/sys_clog2.c b/vpi/sys_clog2.c index 883c9105b..df85720bd 100644 --- a/vpi/sys_clog2.c +++ b/vpi/sys_clog2.c @@ -69,7 +69,7 @@ static PLI_INT32 sys_clog2_compiletf(PLI_BYTE8 *name) /* We must have an argument. */ if (argv == 0) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("$clog2 requires one numeric argument.\n"); vpi_control(vpiFinish, 1); @@ -79,7 +79,7 @@ static PLI_INT32 sys_clog2_compiletf(PLI_BYTE8 *name) /* The argument must be numeric. */ arg = vpi_scan(argv); if (! is_numeric_obj(arg)) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("The first argument to $clog2 must be numeric.\n"); vpi_control(vpiFinish, 1); @@ -90,7 +90,7 @@ static PLI_INT32 sys_clog2_compiletf(PLI_BYTE8 *name) char msg [64]; unsigned argc; - snprintf(msg, 64, "ERROR: %s line %d:", + snprintf(msg, 64, "ERROR: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); diff --git a/vpi/sys_convert.c b/vpi/sys_convert.c index 9c387aabd..d55465791 100644 --- a/vpi/sys_convert.c +++ b/vpi/sys_convert.c @@ -85,7 +85,7 @@ static void double2bits(double real, PLI_UINT32 bits[2]) static void error_message(vpiHandle callh, const char* msg) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf(msg, vpi_get_str(vpiName, callh)); vpi_control(vpiFinish, 1); diff --git a/vpi/sys_display.c b/vpi/sys_display.c index 2a327f60e..36fef11ae 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -2198,6 +2198,27 @@ static PLI_INT32 sys_printtimescale_calltf(PLI_BYTE8*xx) return 0; } +static PLI_INT32 sys_no_aa_compiletf(PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle arg; + /* If there are no arguments, just return. */ + if (argv == 0) return 0; + + for (arg = vpi_scan(argv) ; arg ; arg = vpi_scan(argv)) { + if (vpi_get(vpiAutomatic, arg)) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s arguments may not be automatically " + "allocated variables.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + } + return 0; +} + void sys_display_register() { s_cb_data cb_data; @@ -2273,7 +2294,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$strobe"; tf_data.calltf = sys_strobe_calltf; - tf_data.compiletf = 0; + tf_data.compiletf = sys_no_aa_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$strobe"; vpi_register_systf(&tf_data); @@ -2281,7 +2302,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$strobeh"; tf_data.calltf = sys_strobe_calltf; - tf_data.compiletf = 0; + tf_data.compiletf = sys_no_aa_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$strobeh"; vpi_register_systf(&tf_data); @@ -2289,7 +2310,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$strobeo"; tf_data.calltf = sys_strobe_calltf; - tf_data.compiletf = 0; + tf_data.compiletf = sys_no_aa_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$strobeo"; vpi_register_systf(&tf_data); @@ -2297,7 +2318,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$strobeb"; tf_data.calltf = sys_strobe_calltf; - tf_data.compiletf = 0; + tf_data.compiletf = sys_no_aa_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$strobeb"; vpi_register_systf(&tf_data); @@ -2306,7 +2327,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$fstrobe"; tf_data.calltf = sys_strobe_calltf; - tf_data.compiletf = 0; + tf_data.compiletf = sys_no_aa_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$fstrobe"; vpi_register_systf(&tf_data); @@ -2314,7 +2335,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$fstrobeh"; tf_data.calltf = sys_strobe_calltf; - tf_data.compiletf = 0; + tf_data.compiletf = sys_no_aa_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$fstrobeh"; vpi_register_systf(&tf_data); @@ -2322,7 +2343,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$fstrobeo"; tf_data.calltf = sys_strobe_calltf; - tf_data.compiletf = 0; + tf_data.compiletf = sys_no_aa_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$fstrobeo"; vpi_register_systf(&tf_data); @@ -2330,7 +2351,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$fstrobeb"; tf_data.calltf = sys_strobe_calltf; - tf_data.compiletf = 0; + tf_data.compiletf = sys_no_aa_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$fstrobeb"; vpi_register_systf(&tf_data); @@ -2339,7 +2360,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$monitor"; tf_data.calltf = sys_monitor_calltf; - tf_data.compiletf = 0; + tf_data.compiletf = sys_no_aa_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$monitor"; vpi_register_systf(&tf_data); @@ -2347,7 +2368,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$monitorh"; tf_data.calltf = sys_monitor_calltf; - tf_data.compiletf = 0; + tf_data.compiletf = sys_no_aa_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$monitorh"; vpi_register_systf(&tf_data); @@ -2355,7 +2376,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$monitoro"; tf_data.calltf = sys_monitor_calltf; - tf_data.compiletf = 0; + tf_data.compiletf = sys_no_aa_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$monitoro"; vpi_register_systf(&tf_data); @@ -2363,7 +2384,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$monitorb"; tf_data.calltf = sys_monitor_calltf; - tf_data.compiletf = 0; + tf_data.compiletf = sys_no_aa_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$monitorb"; vpi_register_systf(&tf_data); diff --git a/vpi/sys_fileio.c b/vpi/sys_fileio.c index ac36d9f05..a36ce4978 100644 --- a/vpi/sys_fileio.c +++ b/vpi/sys_fileio.c @@ -41,14 +41,14 @@ static PLI_INT32 sys_fopen_compiletf(PLI_BYTE8 *name) /* Check that there is a file name argument and that it is a string. */ if (argv == 0) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s requires a string file name argument.\n", name); vpi_control(vpiFinish, 1); return 0; } if (! is_string_obj(vpi_scan(argv))) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's file name argument must be a string.\n", name); vpi_control(vpiFinish, 1); @@ -60,7 +60,7 @@ static PLI_INT32 sys_fopen_compiletf(PLI_BYTE8 *name) /* When provided, the type argument must be a string. */ if (! is_string_obj(arg)) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's type argument must be a string.\n", name); vpi_control(vpiFinish, 1); @@ -71,7 +71,7 @@ static PLI_INT32 sys_fopen_compiletf(PLI_BYTE8 *name) char msg [64]; unsigned argc; - snprintf(msg, 64, "ERROR: %s line %d:", + snprintf(msg, 64, "ERROR: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); @@ -106,7 +106,7 @@ static PLI_INT32 sys_fopen_calltf(PLI_BYTE8*name) vpi_get_value(mode, &val); /* Verify that we have a string and that it is not NULL. */ if (val.format != vpiStringVal || !*(val.value.str)) { - vpi_printf("WARNING: %s line %d: ", + vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's mode argument is not a valid string.\n", @@ -116,7 +116,7 @@ static PLI_INT32 sys_fopen_calltf(PLI_BYTE8*name) /* Make sure the mode string is correct. */ if (strlen(val.value.str) > 3) { - vpi_printf("WARNING: %s line %d: ", + vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's mode argument (%s) is too long.\n", @@ -147,7 +147,7 @@ static PLI_INT32 sys_fopen_calltf(PLI_BYTE8*name) if (! fail) break; default: - vpi_printf("WARNING: %s line %d: ", + vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's mode argument (%s) is invalid.\n", @@ -169,7 +169,7 @@ static PLI_INT32 sys_fopen_calltf(PLI_BYTE8*name) /* Verify that we have a string and that it is not NULL. */ if (val.format != vpiStringVal || !*(val.value.str)) { - vpi_printf("WARNING: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's file name argument is not a valid string.\n", name); @@ -185,7 +185,7 @@ static PLI_INT32 sys_fopen_calltf(PLI_BYTE8*name) for (idx = 0; idx < len; idx++) { if (! isprint(val.value.str[idx])) { char msg [64]; - snprintf(msg, 64, "WARNING: %s line %d:", + snprintf(msg, 64, "WARNING: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s %s's file name argument contains non-" @@ -236,7 +236,7 @@ static PLI_INT32 sys_fopenrwa_calltf(PLI_BYTE8*name) /* Verify that we have a string and that it is not NULL. */ if (val.format != vpiStringVal || !*(val.value.str)) { - vpi_printf("WARNING: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's file name argument is not a valid string.\n", name); @@ -251,7 +251,7 @@ static PLI_INT32 sys_fopenrwa_calltf(PLI_BYTE8*name) for (idx = 0; idx < len; idx++) { if (! isprint(val.value.str[idx])) { char msg [64]; - snprintf(msg, 64, "WARNING: %s line %d:", + snprintf(msg, 64, "WARNING: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s %s's file name argument contains non-" @@ -355,7 +355,7 @@ static PLI_INT32 sys_fputc_calltf(PLI_BYTE8*name) fp = vpi_get_file(fd_mcd); val.format = vpiIntVal; if (!fp || IS_MCD(fd_mcd)) { - vpi_printf("WARNING: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd, name); @@ -378,7 +378,7 @@ static PLI_INT32 sys_fgets_compiletf(PLI_BYTE8*name) * register and that the second is numeric. */ if (argv == 0) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s requires two arguments.\n", name); vpi_control(vpiFinish, 1); @@ -386,7 +386,7 @@ static PLI_INT32 sys_fgets_compiletf(PLI_BYTE8*name) } if (vpi_get(vpiType, vpi_scan(argv)) != vpiReg) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's first argument must be a reg.\n", name); vpi_control(vpiFinish, 1); @@ -394,7 +394,7 @@ static PLI_INT32 sys_fgets_compiletf(PLI_BYTE8*name) arg = vpi_scan(argv); if (! arg) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s requires a second (numeric) argument.\n", name); vpi_control(vpiFinish, 1); @@ -402,7 +402,7 @@ static PLI_INT32 sys_fgets_compiletf(PLI_BYTE8*name) } if (! is_numeric_obj(arg)) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's second argument must be numeric.\n", name); vpi_control(vpiFinish, 1); @@ -413,7 +413,7 @@ static PLI_INT32 sys_fgets_compiletf(PLI_BYTE8*name) char msg [64]; unsigned argc; - snprintf(msg, 64, "ERROR: %s line %d:", + snprintf(msg, 64, "ERROR: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); @@ -455,7 +455,7 @@ static PLI_INT32 sys_fgets_calltf(PLI_BYTE8*name) /* Return zero if this is not a valid fd. */ fp = vpi_get_file(fd_mcd); if (!fp || IS_MCD(fd_mcd)) { - vpi_printf("WARNING: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd, name); @@ -519,7 +519,7 @@ static PLI_INT32 sys_ungetc_calltf(PLI_BYTE8*name) /* Return EOF if this is not a valid fd. */ fp = vpi_get_file(fd_mcd); if (!fp || IS_MCD(fd_mcd)) { - vpi_printf("WARNING: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd, name); @@ -545,7 +545,7 @@ static PLI_INT32 sys_fseek_compiletf(PLI_BYTE8*name) /* Check that there are three numeric arguments. */ if (argv == 0) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s requires three arguments.\n", name); vpi_control(vpiFinish, 1); @@ -554,7 +554,7 @@ static PLI_INT32 sys_fseek_compiletf(PLI_BYTE8*name) /* Check that the first argument is numeric. */ if (! is_numeric_obj(vpi_scan(argv))) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's first argument must be numeric.\n", name); vpi_control(vpiFinish, 1); @@ -563,7 +563,7 @@ static PLI_INT32 sys_fseek_compiletf(PLI_BYTE8*name) /* Check that the second argument exists and is numeric. */ arg = vpi_scan(argv); if (! arg) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s requires a second (numeric) argument.\n", name); vpi_control(vpiFinish, 1); @@ -571,7 +571,7 @@ static PLI_INT32 sys_fseek_compiletf(PLI_BYTE8*name) } if (!arg || !is_numeric_obj(arg)) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's second argument must be numeric.\n", name); vpi_control(vpiFinish, 1); @@ -580,7 +580,7 @@ static PLI_INT32 sys_fseek_compiletf(PLI_BYTE8*name) /* Check that the third argument exists and is numeric. */ arg = vpi_scan(argv); if (! arg) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s requires a third (numeric) argument.\n", name); vpi_control(vpiFinish, 1); @@ -588,7 +588,7 @@ static PLI_INT32 sys_fseek_compiletf(PLI_BYTE8*name) } if (!arg || !is_numeric_obj(arg)) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's third argument must be numeric.\n", name); vpi_control(vpiFinish, 1); @@ -599,7 +599,7 @@ static PLI_INT32 sys_fseek_compiletf(PLI_BYTE8*name) char msg [64]; unsigned argc; - snprintf(msg, 64, "ERROR: %s line %d:", + snprintf(msg, 64, "ERROR: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); @@ -647,7 +647,7 @@ static PLI_INT32 sys_fseek_calltf(PLI_BYTE8*name) /* Check that the operation is in the valid range. */ if ((oper < 0) || (oper > 2)) { - vpi_printf("WARNING: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's operation must be 0, 1 or 2 given %d.\n", name, oper); @@ -660,7 +660,7 @@ static PLI_INT32 sys_fseek_calltf(PLI_BYTE8*name) /* Return EOF if this is not a valid fd. */ fp = vpi_get_file(fd_mcd); if (!fp || IS_MCD(fd_mcd)) { - vpi_printf("WARNING: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd, name); @@ -696,7 +696,7 @@ static PLI_INT32 sys_common_fd_calltf(PLI_BYTE8*name) /* Return EOF if this is not a valid fd. */ fp = vpi_get_file(fd_mcd); if (!fp || IS_MCD(fd_mcd)) { - vpi_printf("WARNING: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd, name); @@ -721,7 +721,7 @@ static PLI_INT32 sys_common_fd_calltf(PLI_BYTE8*name) val.value.integer = fgetc(fp); break; default: - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s cannot be processed with this routine.\n", name); assert(0); diff --git a/vpi/sys_lxt.c b/vpi/sys_lxt.c index b3bdb73f7..f0ce99855 100644 --- a/vpi/sys_lxt.c +++ b/vpi/sys_lxt.c @@ -435,7 +435,7 @@ static void open_dumpfile(vpiHandle callh) dump_file = lt_init(dump_path); if (dump_file == 0) { - vpi_printf("LXT Error: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("LXT Error: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("Unable to open %s for output.\n", dump_path); vpi_control(vpiFinish, 1); diff --git a/vpi/sys_lxt2.c b/vpi/sys_lxt2.c index 73135db04..2e3fb0fb8 100644 --- a/vpi/sys_lxt2.c +++ b/vpi/sys_lxt2.c @@ -433,7 +433,7 @@ static void open_dumpfile(vpiHandle callh) dump_file = lxt2_wr_init(dump_path); if (dump_file == 0) { - vpi_printf("LXT2 Error: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("LXT2 Error: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("Unable to open %s for output.\n", dump_path); vpi_control(vpiFinish, 1); diff --git a/vpi/sys_plusargs.c b/vpi/sys_plusargs.c index 9847f036a..9c6d53934 100644 --- a/vpi/sys_plusargs.c +++ b/vpi/sys_plusargs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-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,87 +16,32 @@ * 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_plusargs.c,v 1.7 2007/03/14 04:05:51 steve Exp $" -#endif +# include "sys_priv.h" # include # include # include # include -static PLI_INT32 sys_plusargs_sizetf(PLI_BYTE8*x) -{ - return 32; -} - -/* - * The compiletf for $test$plusargs checks that there is one argument - * to the function call, and that argument is a constant string. - */ -static PLI_INT32 sys_test_plusargs_compiletf(PLI_BYTE8*xx) -{ - vpiHandle sys = vpi_handle(vpiSysTfCall, 0); - vpiHandle argv = vpi_iterate(vpiArgument, sys); - vpiHandle arg; - - if (argv == 0) { - vpi_printf("ERROR: $test$plusargs requires one argument\n"); - vpi_control(vpiFinish, 1); - return 0; - } - - arg = vpi_scan(argv); - assert(arg != 0); - - switch (vpi_get(vpiType, arg)) { - case vpiConstant: - if (vpi_get(vpiConstType, arg) != vpiStringConst) { - vpi_printf("ERROR: Argument of $test$plusargs " - " must be a constant string.\n"); - vpi_control(vpiFinish, 1); - return 0; - } - break; - - default: - vpi_printf("ERROR: Argument of $test$plusargs " - " must be a constant string.\n"); - vpi_control(vpiFinish, 1); - return 0; - } - - - arg = vpi_scan(argv); - if (arg != 0) { - vpi_printf("ERROR: too many arguments to $test$plusargs\n"); - vpi_control(vpiFinish, 1); - } - - return 0; -} - /* * Compare the +arguments passed to the simulator with the argument * passed to the $test$plusargs. If there is a simulator argument that * is like this argument, then return true. Otherwise return false. */ -static PLI_INT32 sys_test_plusargs_calltf(PLI_BYTE8*xx) +static PLI_INT32 sys_test_plusargs_calltf(PLI_BYTE8*name) { + s_vpi_value val; + s_vpi_vlog_info info; int idx; int flag = 0; size_t slen, len; - s_vpi_vlog_info info; - s_vpi_value value; - s_vpi_value result; - vpiHandle sys = vpi_handle(vpiSysTfCall, 0); - vpiHandle argv = vpi_iterate(vpiArgument, sys); - vpiHandle arg = vpi_scan(argv); + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); - value.format = vpiStringVal; - vpi_get_value(arg, &value); - slen = strlen(value.value.str); + val.format = vpiStringVal; + vpi_get_value(vpi_scan(argv), &val); + slen = strlen(val.value.str); vpi_get_vlog_info(&info); @@ -111,97 +56,52 @@ static PLI_INT32 sys_test_plusargs_calltf(PLI_BYTE8*xx) if (len < slen) continue; - if (strncmp(value.value.str, info.argv[idx]+1, slen) != 0) + if (strncmp(val.value.str, info.argv[idx]+1, slen) != 0) continue; flag = 1; break; } - result.format = vpiIntVal; - result.value.integer = flag; - vpi_put_value(sys, &result, 0, vpiNoDelay); + val.format = vpiIntVal; + val.value.integer = flag; + vpi_put_value(callh, &val, 0, vpiNoDelay); + vpi_free_object(argv); return 0; } -static PLI_INT32 sys_value_plusargs_compiletf(PLI_BYTE8*xx) +static PLI_INT32 sys_value_plusargs_compiletf(PLI_BYTE8*name) { - s_vpi_value value; - vpiHandle sys = vpi_handle(vpiSysTfCall, 0); - vpiHandle argv = vpi_iterate(vpiArgument, sys); + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle arg; + /* Check that there are arguments. */ if (argv == 0) { - vpi_printf("ERROR: $value$plusargs requires two arguments\n"); + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s requires two arguments.\n", name); vpi_control(vpiFinish, 1); return 0; } + /* Check that the first argument is a string. */ arg = vpi_scan(argv); assert(arg != 0); - - switch (vpi_get(vpiType, arg)) { - case vpiConstant: - if (vpi_get(vpiConstType, arg) != vpiStringConst) { - vpi_printf("ERROR: First argument of $value$plusargs " - " must be a constant string.\n"); - vpi_control(vpiFinish, 1); - return 0; - } - break; - - default: - vpi_printf("ERROR: First argument of $value$plusargs " - " must be a constant string.\n"); + if ( ! is_string_obj(arg)) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s's first argument must be a string.\n", name); vpi_control(vpiFinish, 1); return 0; - break; - } - - /* Check that the format string has a reasonable format. */ - value.format = vpiStringVal; - vpi_get_value(arg, &value); - { char*fmt = value.value.str; - char*cp = strchr(fmt, '%'); - - if (cp == 0) { - vpi_printf("ERROR: Invalid argument format string" - ": %s\n", fmt); - vpi_control(vpiFinish, 1); - return 0; - } - - cp += 1; - if (*cp == '0') - cp += 1; - - switch (*cp) { - case 'd': - case 'o': - case 'b': - case 'h': - case 's': - cp += 1; - break; - default: - vpi_printf("ERROR: Invalid argument format string" - ": %s\n", fmt); - vpi_control(vpiFinish, 1); - return 0; - } - - if (*cp != 0) { - vpi_printf("ERROR: Trailing junk after value format" - ": %s\n", fmt); - vpi_control(vpiFinish, 1); - return 0; - } } arg = vpi_scan(argv); - if (argv == 0) { - vpi_printf("ERROR: $value$plusargs requires two arguments\n"); + if (! arg) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s's requires a second variable argument.\n", name); vpi_control(vpiFinish, 1); return 0; } @@ -210,55 +110,129 @@ static PLI_INT32 sys_value_plusargs_compiletf(PLI_BYTE8*xx) case vpiReg: case vpiIntegerVar: + case vpiRealVar: + case vpiTimeVar: break; default: - vpi_printf("ERROR: value field doesn\'t match format: %s\n", - value.value.str); + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s's second argument must be a variable, found a %s.\n", + name, vpi_get_str(vpiType, arg)); vpi_control(vpiFinish, 1); return 0; } - arg = vpi_scan(argv); - if (arg != 0) { - vpi_printf("ERROR: too many arguments to $value$plusargs\n"); + /* Make sure there are no extra arguments. */ + if (vpi_scan(argv) != 0) { + char msg [64]; + unsigned argc; + + snprintf(msg, 64, "ERROR: %s:%d:", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + + argc = 1; + while (vpi_scan(argv)) argc += 1; + + vpi_printf("%s %s takes two arguments.\n", msg, name); + vpi_printf("%*s Found %u extra argument%s.\n", + (int)strlen(msg), " ", argc, argc == 1 ? "" : "s"); vpi_control(vpiFinish, 1); - return 0; } return 0; } -static PLI_INT32 sys_value_plusargs_calltf(PLI_BYTE8*xx) +static PLI_INT32 sys_value_plusargs_calltf(PLI_BYTE8*name) { + s_vpi_vlog_info info; + s_vpi_value fmt; + s_vpi_value res; + char msg [64]; char*cp; int idx; int flag = 0; size_t slen, len; - s_vpi_vlog_info info; - s_vpi_value format; - s_vpi_value result; - vpiHandle sys = vpi_handle(vpiSysTfCall, 0); - vpiHandle argv = vpi_iterate(vpiArgument, sys); - vpiHandle arg1 = vpi_scan(argv); - vpiHandle arg2 = vpi_scan(argv); + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); - format.format = vpiStringVal; - vpi_get_value(arg1, &format); + fmt.format = vpiStringVal; + vpi_get_value(vpi_scan(argv), &fmt); + + /* Check for the start of a format string. */ + cp = strchr(fmt.value.str, '%'); + if (cp == 0) { + snprintf(msg, 64, "ERROR: %s:%d:", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + + vpi_printf("%s %s is missing a format code.\n", msg, name); + vpi_printf("%*s \"%s\".\n", (int)strlen(msg), " ", fmt.value.str); + vpi_control(vpiFinish, 1); + return 0; + } + + /* This is the length of string we will look for. */ + slen = cp - fmt.value.str; + + /* Skip a zero. */ + cp += 1; + if (*cp == '0') cp += 1; + + /* Check the format code. */ + switch (*cp) { + case 'd': + case 'D': + case 'o': + case 'O': + case 'h': + case 'H': + case 'x': + case 'X': + case 'b': + case 'B': + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + case 's': + case 'S': + break; + default: + snprintf(msg, 64, "ERROR: %s:%d:", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + + vpi_printf("%s %s has an invalid format string:\n", msg, name); + vpi_printf("%*s \"%s\".\n", (int)strlen(msg), " ", fmt.value.str); + vpi_control(vpiFinish, 1); + return 0; + } + + /* Warn if there is any trailing garbage. */ + if (*(cp+1) != '\0') { + snprintf(msg, 64, "WARNING: %s:%d:", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + + vpi_printf("%s Skipping trailing garbage in %s's format string:\n", + msg, name); + vpi_printf("%*s \"%s\".\n", (int)strlen(msg), " ", fmt.value.str); + *(cp+1) = '\0'; + } vpi_get_vlog_info(&info); - cp = strchr(format.value.str, '%'); - assert(cp); - slen = cp - format.value.str; - - cp += 1; - if (*cp == '0') - cp += 1; - + /* Look for a +arg that matches the prefix supplied. */ for (idx = 0 ; idx < info.argc ; idx += 1) { + char*sp, *tp, *end; + size_t sp_len; + /* Skip arguments that are not +args. */ if (info.argv[idx][0] != '+') continue; @@ -266,43 +240,146 @@ static PLI_INT32 sys_value_plusargs_calltf(PLI_BYTE8*xx) if (len < slen) continue; - if (strncmp(format.value.str, info.argv[idx]+1, slen) != 0) + if (strncmp(fmt.value.str, info.argv[idx]+1, slen) != 0) continue; + sp = info.argv[idx]+1+slen; + sp_len = strlen(sp); switch (*cp) { case 'd': - result.format = vpiIntVal; - result.value.integer = strtoul(info.argv[idx]+1+slen,0,10); + case 'D': + res.format = vpiDecStrVal; + /* A decimal string can set the value to "x" or "z". */ + if (sp_len == strspn(sp, "xX_") || + sp_len == strspn(sp, "zZ_")) { + res.value.str = sp; + /* A decimal string must contain only these characters. + * A decimal string can not start with an "_" character. + * A "-" can only be at the start of the string. */ + } else if (sp_len != strspn(sp, "-0123456789_") || + *sp == '_' || + ((tp = strrchr(sp, '-')) && tp != sp)) { + res.value.str = "x"; + snprintf(msg, 64, "WARNING: %s:%d:", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s Invalid decimal value passed to %s:\n", + msg, name); + vpi_printf("%*s \"%s\".\n", (int)strlen(msg), " ", sp); + } else { + res.value.str = sp; + } break; case 'o': - result.format = vpiIntVal; - result.value.integer = strtoul(info.argv[idx]+1+slen,0,8); + case 'O': + res.format = vpiOctStrVal; + /* An octal string must contain only these characters. + * An octal string can not start with an "_" character. + * A "-" can only be at the start of the string. */ + if (sp_len != strspn(sp, "-01234567_xXzZ") || + *sp == '_' || ((tp = strrchr(sp, '-')) && tp != sp)) { + res.value.str = "x"; + snprintf(msg, 64, "WARNING: %s:%d:", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s Invalid octal value passed to %s:\n", + msg, name); + vpi_printf("%*s \"%s\".\n", (int)strlen(msg), " ", sp); + } else { + res.value.str = sp; + } break; case 'h': - result.format = vpiIntVal; - result.value.integer = strtoul(info.argv[idx]+1+slen,0,16); + case 'H': + case 'x': + case 'X': + res.format = vpiHexStrVal; + /* A hex. string must contain only these characters. + * A hex. string can not start with an "_" character. + * A "-" can only be at the start of the string. */ + if (sp_len != strspn(sp, "-0123456789aAbBcCdDeEfF_xXzZ") || + *sp == '_' || ((tp = strrchr(sp, '-')) && tp != sp)) { + res.value.str = "x"; + snprintf(msg, 64, "WARNING: %s:%d:", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s Invalid hex value passed to %s:\n", + msg, name); + vpi_printf("%*s \"%s\".\n", (int)strlen(msg), " ", sp); + } else { + res.value.str = sp; + } break; case 'b': - result.format = vpiIntVal; - result.value.integer = strtoul(info.argv[idx]+1+slen,0,12); + case 'B': + res.format = vpiBinStrVal; + /* A binary string must contain only these characters. + * A binary string can not start with an "_" character. + * A "-" can only be at the start of the string. */ + if (sp_len != strspn(sp, "-01_xXzZ") || + *sp == '_' || ((tp = strrchr(sp, '-')) && tp != sp)) { + res.value.str = "x"; + snprintf(msg, 64, "WARNING: %s:%d:", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s Invalid binary value passed to %s:\n", + msg, name); + vpi_printf("%*s \"%s\".\n", (int)strlen(msg), " ", sp); + } else { + res.value.str = sp; + } + break; + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + res.format = vpiRealVal; + res.value.real = strtod(sp, &end); + /* If we didn't get a full conversion print a warning. */ + if (*end) { + /* We had an invalid value passed. */ + if (end == sp) { + snprintf(msg, 64, "WARNING: %s:%d:", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s Invalid real value passed to " + "%s:\n", msg, name); + vpi_printf("%*s \"%s\".\n", (int)strlen(msg), " ", + sp); + /* We have extra garbage at the end. */ + } else { + snprintf(msg, 64, "WARNING: %s:%d:", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s Extra character(s) \"%s\" found " + "in %s's real string:\n", + msg, end, name); + vpi_printf("%*s \"%s\".\n", (int)strlen(msg), " ", + sp); + } + } break; case 's': - result.format = vpiStringVal; - result.value.str = info.argv[idx]+1+slen; + case 'S': + res.format = vpiStringVal; + res.value.str = sp; break; default: assert(0); } - vpi_put_value(arg2, &result, 0, vpiNoDelay); + vpi_put_value(vpi_scan(argv), &res, 0, vpiNoDelay); flag = 1; break; } - result.format = vpiIntVal; - result.value.integer = flag; - vpi_put_value(sys, &result, 0, vpiNoDelay); + res.format = vpiIntVal; + res.value.integer = flag; + vpi_put_value(callh, &res, 0, vpiNoDelay); + vpi_free_object(argv); return 0; } @@ -311,44 +388,22 @@ void sys_plusargs_register() s_vpi_systf_data tf_data; - tf_data.type = vpiSysFunc; - tf_data.tfname = "$test$plusargs"; - tf_data.calltf = sys_test_plusargs_calltf; - tf_data.compiletf = sys_test_plusargs_compiletf; - tf_data.sizetf = sys_plusargs_sizetf; + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiIntFunc; + tf_data.tfname = "$test$plusargs"; + tf_data.calltf = sys_test_plusargs_calltf; + tf_data.compiletf = sys_one_string_arg_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$test$plusargs"; vpi_register_systf(&tf_data); - tf_data.type = vpiSysFunc; - tf_data.tfname = "$value$plusargs"; - tf_data.calltf = sys_value_plusargs_calltf; - tf_data.compiletf = sys_value_plusargs_compiletf; - tf_data.sizetf = sys_plusargs_sizetf; + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiIntFunc; + tf_data.tfname = "$value$plusargs"; + tf_data.calltf = sys_value_plusargs_calltf; + tf_data.compiletf = sys_value_plusargs_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$value$plusargs"; vpi_register_systf(&tf_data); } - -/* - * $Log: sys_plusargs.c,v $ - * Revision 1.7 2007/03/14 04:05:51 steve - * VPI tasks take PLI_BYTE* by the standard. - * - * Revision 1.6 2006/10/30 22:45:37 steve - * Updates for Cygwin portability (pr1585922) - * - * Revision 1.5 2004/10/04 01:10:58 steve - * Clean up spurious trailing white space. - * - * Revision 1.4 2002/08/12 01:35:05 steve - * conditional ident string using autoconfig. - * - * Revision 1.3 2002/08/11 23:47:04 steve - * Add missing Log and Ident strings. - * - * Revision 1.2 2002/08/10 17:00:31 steve - * Allow vpiIntegerVar as parameter to $value$plusarg - * - * Revision 1.1 2002/04/07 04:37:53 steve - * Add $plusargs system functions. - * - */ - diff --git a/vpi/sys_priv.c b/vpi/sys_priv.c index 6b008844a..2535a84b6 100644 --- a/vpi/sys_priv.c +++ b/vpi/sys_priv.c @@ -80,7 +80,7 @@ unsigned is_numeric_obj(vpiHandle obj) case vpiRealVar: case vpiReg: case vpiTimeVar: - rtn = 1;; + rtn = 1; break; } @@ -114,7 +114,7 @@ unsigned is_string_obj(vpiHandle obj) case vpiPartSelect: case vpiReg: case vpiTimeVar: - rtn = 1;; + rtn = 1; break; } @@ -152,7 +152,7 @@ PLI_INT32 sys_no_arg_compiletf(PLI_BYTE8 *name) char msg [64]; unsigned argc; - snprintf(msg, 64, "ERROR: %s line %d:", + snprintf(msg, 64, "ERROR: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); @@ -176,7 +176,7 @@ PLI_INT32 sys_one_numeric_arg_compiletf(PLI_BYTE8 *name) /* 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), + vpi_printf("ERROR: %s:%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); @@ -184,7 +184,7 @@ PLI_INT32 sys_one_numeric_arg_compiletf(PLI_BYTE8 *name) } if (! is_numeric_obj(vpi_scan(argv))) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%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); @@ -195,7 +195,7 @@ PLI_INT32 sys_one_numeric_arg_compiletf(PLI_BYTE8 *name) char msg [64]; unsigned argc; - snprintf(msg, 64, "ERROR: %s line %d:", + snprintf(msg, 64, "ERROR: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); @@ -221,7 +221,7 @@ PLI_INT32 sys_one_opt_numeric_arg_compiletf(PLI_BYTE8 *name) if (argv == 0) return 0; if (! is_numeric_obj(vpi_scan(argv))) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%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); @@ -232,7 +232,7 @@ PLI_INT32 sys_one_opt_numeric_arg_compiletf(PLI_BYTE8 *name) char msg [64]; unsigned argc; - snprintf(msg, 64, "ERROR: %s line %d:", + snprintf(msg, 64, "ERROR: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); @@ -258,7 +258,7 @@ PLI_INT32 sys_two_numeric_args_compiletf(PLI_BYTE8 *name) /* Check that there are two argument and that they are numeric. */ if (argv == 0) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s requires two numeric arguments.\n", name); vpi_control(vpiFinish, 1); @@ -266,7 +266,7 @@ PLI_INT32 sys_two_numeric_args_compiletf(PLI_BYTE8 *name) } if (! is_numeric_obj(vpi_scan(argv))) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's first argument must be numeric.\n", name); vpi_control(vpiFinish, 1); @@ -274,7 +274,7 @@ PLI_INT32 sys_two_numeric_args_compiletf(PLI_BYTE8 *name) arg = vpi_scan(argv); if (! arg) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s requires a second (numeric) argument.\n", name); vpi_control(vpiFinish, 1); @@ -282,7 +282,7 @@ PLI_INT32 sys_two_numeric_args_compiletf(PLI_BYTE8 *name) } if (! is_numeric_obj(arg)) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's second argument must be numeric.\n", name); vpi_control(vpiFinish, 1); @@ -293,7 +293,7 @@ PLI_INT32 sys_two_numeric_args_compiletf(PLI_BYTE8 *name) char msg [64]; unsigned argc; - snprintf(msg, 64, "ERROR: %s line %d:", + snprintf(msg, 64, "ERROR: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); @@ -317,14 +317,14 @@ PLI_INT32 sys_one_string_arg_compiletf(PLI_BYTE8 *name) /* Check that there is an argument and that it is a string. */ if (argv == 0) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s requires a single string argument.\n", name); vpi_control(vpiFinish, 1); return 0; } if (! is_string_obj(vpi_scan(argv))) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's argument must be a string.\n", name); vpi_control(vpiFinish, 1); @@ -335,7 +335,7 @@ PLI_INT32 sys_one_string_arg_compiletf(PLI_BYTE8 *name) char msg [64]; unsigned argc; - snprintf(msg, 64, "ERROR: %s line %d:", + snprintf(msg, 64, "ERROR: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); diff --git a/vpi/sys_vcd.c b/vpi/sys_vcd.c index c77044ed4..be2cfd14f 100644 --- a/vpi/sys_vcd.c +++ b/vpi/sys_vcd.c @@ -378,7 +378,7 @@ static void open_dumpfile(vpiHandle callh) dump_file = fopen(dump_path, "w"); if (dump_file == 0) { - vpi_printf("VCD Error: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("VCD Error: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("Unable to open %s for output.\n", dump_path); vpi_control(vpiFinish, 1); @@ -677,7 +677,7 @@ static int draw_scope(vpiHandle item, vpiHandle callh) case vpiNamedFork: type = "fork"; break; case vpiModule: type = "module"; break; default: - vpi_printf("VCD Error: %s line %d: $dumpvars: Unsupported scope " + vpi_printf("VCD Error: %s:%d: $dumpvars: Unsupported scope " "type (%d)\n", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh), vpi_get(vpiType, item)); assert(0); diff --git a/vpi/vams_simparam.c b/vpi/vams_simparam.c index d39206227..41ea01357 100644 --- a/vpi/vams_simparam.c +++ b/vpi/vams_simparam.c @@ -44,7 +44,7 @@ static PLI_INT32 simparam_compiletf(PLI_BYTE8 *name_ext) /* We must have at least one argument. */ if (argv == 0) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("$simparam%s requires a string argument.\n", name_ext); vpi_control(vpiFinish, 1); @@ -54,7 +54,7 @@ static PLI_INT32 simparam_compiletf(PLI_BYTE8 *name_ext) /* The first argument must be a string. */ arg = vpi_scan(argv); if (! is_string_obj(arg)) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("The first argument to $simparam%s must be a string.\n", name_ext); @@ -68,7 +68,7 @@ static PLI_INT32 simparam_compiletf(PLI_BYTE8 *name_ext) /* For the string version the default must also be a string. */ if (strcmp(name_ext, "$str") == 0) { if (! is_string_obj(arg)) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%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", name_ext); @@ -77,7 +77,7 @@ static PLI_INT32 simparam_compiletf(PLI_BYTE8 *name_ext) /* For the rest the default must be numeric. */ } else { if (! is_numeric_obj(arg)) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%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", name_ext); @@ -90,7 +90,7 @@ static PLI_INT32 simparam_compiletf(PLI_BYTE8 *name_ext) char msg [64]; unsigned argc; - snprintf(msg, 64, "ERROR: %s line %d:", + snprintf(msg, 64, "ERROR: %s:%d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); @@ -164,7 +164,7 @@ static PLI_INT32 simparam_calltf(PLI_BYTE8 *name_ext) retval = 8.0*sizeof(long); } else { if (! have_def_val) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("$simparam%s unknown parameter name \"%s\".\n", name_ext, param); @@ -229,7 +229,7 @@ static PLI_INT32 simparam_str_calltf(PLI_BYTE8 *name_ext) vpi_handle(vpiScope,callh))); } else { if (defval == 0) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("$simparam%s unknown parameter name \"%s\".\n", name_ext, param); diff --git a/vpi/vcd_priv.c b/vpi/vcd_priv.c index ad4276c8f..9f59d741e 100644 --- a/vpi/vcd_priv.c +++ b/vpi/vcd_priv.c @@ -204,7 +204,7 @@ PLI_INT32 sys_dumpvars_compiletf(PLI_BYTE8 *name) /* The first argument is the numeric level. */ if (! is_numeric_obj(vpi_scan(argv))) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%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); @@ -215,7 +215,7 @@ PLI_INT32 sys_dumpvars_compiletf(PLI_BYTE8 *name) switch(vpi_get(vpiType, arg)) { case vpiMemoryWord: if (vpi_get(vpiConstantSelect, arg) == 0) { - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s cannot dump a non-constant select %s.\n", name, vpi_get_str(vpiType, arg)); @@ -235,7 +235,7 @@ PLI_INT32 sys_dumpvars_compiletf(PLI_BYTE8 *name) case vpiRealVar: break; default: - vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s cannot dump a %s.\n", name, vpi_get_str(vpiType, arg)); diff --git a/vvp/array.cc b/vvp/array.cc index 0cd51b5ff..1da9117f7 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -454,6 +454,9 @@ static int vpi_array_var_word_get(int code, vpiHandle ref) case vpiRightRange: return parent->lsb.value; + case vpiAutomatic: + return (int) parent->scope->is_automatic; + default: return 0; } @@ -634,6 +637,9 @@ static int vpi_array_vthr_A_get(int code, vpiHandle ref) case vpiRightRange: return parent->lsb.value; + case vpiAutomatic: + return (int) parent->scope->is_automatic; + // For now &A<> is only a constant select. This will need // to be changed when it supports variable selection. case vpiConstantSelect: diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index c99cf3b03..4ddc08d50 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -119,6 +119,14 @@ void delete_vpi_callback(struct __vpiCallback* ref) */ 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(); obj->cb_data = *data; if (data->time) { diff --git a/vvp/vpi_const.cc b/vvp/vpi_const.cc index 75c96be8d..44d7f0e05 100644 --- a/vvp/vpi_const.cc +++ b/vvp/vpi_const.cc @@ -47,6 +47,9 @@ static int string_get(int code, vpiHandle ref) case vpiConstType: return vpiStringConst; + case vpiAutomatic: + return 0; + default: fprintf(stderr, "vvp error: get %d not supported " "by vpiStringConst\n", code); @@ -343,6 +346,9 @@ static int binary_get(int code, vpiHandle ref) case vpiSize: return rfp->bits.size(); + case vpiAutomatic: + return 0; + default: fprintf(stderr, "vvp error: get %d not supported " "by vpiBinaryConst\n", code); @@ -533,6 +539,9 @@ static int dec_get(int code, vpiHandle ref) case vpiSize: return 32; + case vpiAutomatic: + return 0; + default: fprintf(stderr, "vvp error: get %d not supported " "by vpiDecConst\n", code); @@ -636,6 +645,9 @@ static int real_get(int code, vpiHandle ref) case vpiSigned: return 1; + case vpiAutomatic: + return 0; + default: fprintf(stderr, "vvp error: get %d not supported " "by vpiDecConst\n", code); diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index 27af301cf..321b1109e 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -692,6 +692,14 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp, if (flags!=vpiNoDelay && flags!=vpiForceFlag && flags!=vpiReleaseFlag) { 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); switch (when->type) { diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index a9ffd0369..d8d6305db 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -223,7 +223,6 @@ struct __vpiSignal { unsigned signed_flag : 1; unsigned isint_ : 1; // original type was integer unsigned is_netarray : 1; // This is word of a net array - unsigned is_automatic : 1; /* The represented value is here. */ vvp_net_t*node; }; @@ -563,8 +562,6 @@ extern unsigned vpip_vec4_to_dec_str(const vvp_vector4_t&vec4, char *buf, unsigned int nbuf, int signed_flag); -extern void vpip_bin_str_to_vec4(vvp_vector4_t&val, - const char*buf, bool signed_flag); extern void vpip_vec4_to_hex_str(const vvp_vector4_t&bits, char*buf, unsigned nbuf, bool signed_flag); @@ -572,8 +569,9 @@ extern void vpip_vec4_to_hex_str(const vvp_vector4_t&bits, char*buf, extern void vpip_vec4_to_oct_str(const vvp_vector4_t&bits, char*buf, unsigned nbuf, bool signed_flag); +extern void vpip_bin_str_to_vec4(vvp_vector4_t&val, const char*buf); extern void vpip_oct_str_to_vec4(vvp_vector4_t&val, const char*str); -extern void vpip_dec_str_to_vec4(vvp_vector4_t&val, const char*str, bool sign); +extern void vpip_dec_str_to_vec4(vvp_vector4_t&val, const char*str); extern void vpip_hex_str_to_vec4(vvp_vector4_t&val, const char*str); extern vvp_vector4_t vec4_from_vpi_value(s_vpi_value*vp, unsigned wid); diff --git a/vvp/vpi_real.cc b/vvp/vpi_real.cc index a0c83d466..0f8aa2d4e 100644 --- a/vvp/vpi_real.cc +++ b/vvp/vpi_real.cc @@ -136,23 +136,37 @@ static void real_var_get_value(vpiHandle ref, s_vpi_value*vp) static vpiHandle real_var_put_value(vpiHandle ref, p_vpi_value vp, int) { + vvp_vector4_t vec4(1024); + double result; + bool is_signed = false; assert(ref->vpi_type->type_code == vpiRealVar); - struct __vpiRealVar*rfp - = (struct __vpiRealVar*)ref; - - vvp_net_ptr_t destination (rfp->net, 0); - switch (vp->format) { - case vpiRealVal: - vvp_send_real(destination, vp->value.real, - vthread_get_wt_context()); + result = vp->value.real; break; - case vpiIntVal: - vvp_send_real(destination, (double)vp->value.integer, - vthread_get_wt_context()); + result = (double)vp->value.integer; + break; + case vpiBinStrVal: + vpip_bin_str_to_vec4(vec4, vp->value.str); + if (vp->value.str[0] == '-') is_signed = true; + vector4_to_value(vec4, result, is_signed); + break; + case vpiOctStrVal: + vpip_oct_str_to_vec4(vec4, vp->value.str); + if (vp->value.str[0] == '-') is_signed = true; + vector4_to_value(vec4, result, is_signed); + break; + case vpiDecStrVal: + vpip_dec_str_to_vec4(vec4, vp->value.str); + if (vp->value.str[0] == '-') is_signed = true; + vector4_to_value(vec4, result, is_signed); + break; + case vpiHexStrVal: + vpip_hex_str_to_vec4(vec4, vp->value.str); + if (vp->value.str[0] == '-') is_signed = true; + vector4_to_value(vec4, result, is_signed); break; default: @@ -160,8 +174,12 @@ static vpiHandle real_var_put_value(vpiHandle ref, p_vpi_value vp, int) vp->format); assert(0); break; - } + + struct __vpiRealVar*rfp = (struct __vpiRealVar*)ref; + assert(rfp); + vvp_net_ptr_t destination (rfp->net, 0); + vvp_send_real(destination, result, vthread_get_wt_context()); return 0; } diff --git a/vvp/vpi_scope.cc b/vvp/vpi_scope.cc index f12103753..a03245108 100644 --- a/vvp/vpi_scope.cc +++ b/vvp/vpi_scope.cc @@ -75,6 +75,9 @@ static int scope_get(int code, vpiHandle obj) case vpiTopModule: return 0x0 == ref->scope; + + case vpiAutomatic: + return (int) ref->is_automatic; } return 0; @@ -330,33 +333,29 @@ compile_scope_decl(char*label, char*type, char*name, const char*tname, struct __vpiScope*scope = new struct __vpiScope; 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->is_automatic = false; - } else if (strcmp(type,"autofunction") == 0) { + } else if (strcmp(base_type,"function") == 0) { scope->base.vpi_type = &vpip_scope_function_rt; - scope->is_automatic = true; - } else if (strcmp(type,"function") == 0) { - scope->base.vpi_type = &vpip_scope_function_rt; - scope->is_automatic = false; - } else if (strcmp(type,"autotask") == 0) { + } else if (strcmp(base_type,"task") == 0) { scope->base.vpi_type = &vpip_scope_task_rt; - scope->is_automatic = true; - } else if (strcmp(type,"task") == 0) { - scope->base.vpi_type = &vpip_scope_task_rt; - scope->is_automatic = false; - } else if (strcmp(type,"fork") == 0) { + } else if (strcmp(base_type,"fork") == 0) { scope->base.vpi_type = &vpip_scope_fork_rt; - scope->is_automatic = false; - } else if (strcmp(type,"begin") == 0) { + } else if (strcmp(base_type,"begin") == 0) { scope->base.vpi_type = &vpip_scope_begin_rt; - scope->is_automatic = false; - } else if (strcmp(type,"generate") == 0) { + } else if (strcmp(base_type,"generate") == 0) { scope->base.vpi_type = &vpip_scope_begin_rt; - scope->is_automatic = false; } else { scope->base.vpi_type = &vpip_scope_module_rt; - scope->is_automatic = false; 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_precision = sp->time_precision; - /* Scopes within automatic scopes are themselves automatic. */ - if (sp->is_automatic) - scope->is_automatic = true; - } else { 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. */ return 2 + idx; } - - diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index 575372434..a46303228 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -528,10 +528,14 @@ static int signal_get(int code, vpiHandle ref) else return 0; - case vpiLeftRange: return rfp->msb; - case vpiRightRange: return rfp->lsb; + case vpiLeftRange: + 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: if (rfp->msb == rfp->lsb) @@ -800,13 +804,13 @@ vvp_vector4_t vec4_from_vpi_value(s_vpi_value*vp, unsigned wid) } break; case vpiBinStrVal: - vpip_bin_str_to_vec4(val, vp->value.str, false); + vpip_bin_str_to_vec4(val, vp->value.str); break; case vpiOctStrVal: vpip_oct_str_to_vec4(val, vp->value.str); break; case vpiDecStrVal: - vpip_dec_str_to_vec4(val, vp->value.str, false); + vpip_dec_str_to_vec4(val, vp->value.str); break; case vpiHexStrVal: vpip_hex_str_to_vec4(val, vp->value.str); @@ -817,6 +821,9 @@ vvp_vector4_t vec4_from_vpi_value(s_vpi_value*vp, unsigned wid) case vpiStringVal: val = from_stringval(vp->value.str, wid); break; + case vpiRealVal: + val = vvp_vector4_t(wid, vp->value.real); + break; default: fprintf(stderr, "vvp internal error: put_value: " @@ -863,7 +870,6 @@ vpiHandle vpip_make_int(const char*name, int msb, int lsb, vvp_net_t*vec) struct __vpiSignal*rfp = (struct __vpiSignal*)obj; obj->vpi_type = &vpip_reg_rt; rfp->isint_ = true; - rfp->is_automatic = vpip_peek_current_scope()->is_automatic; return obj; } @@ -874,9 +880,7 @@ vpiHandle vpip_make_reg(const char*name, int msb, int lsb, bool signed_flag, vvp_net_t*vec) { vpiHandle obj = vpip_make_net(name, msb,lsb, signed_flag, vec); - struct __vpiSignal*rfp = (struct __vpiSignal*)obj; obj->vpi_type = &vpip_reg_rt; - rfp->is_automatic = vpip_peek_current_scope()->is_automatic; return obj; } @@ -915,7 +919,6 @@ vpiHandle vpip_make_net(const char*name, int msb, int lsb, obj->signed_flag = signed_flag? 1 : 0; obj->isint_ = 0; obj->is_netarray = 0; - obj->is_automatic = vpip_peek_current_scope()->is_automatic; obj->node = node; // Place this object within a scope. If this object is @@ -972,11 +975,15 @@ static int PV_get(int code, vpiHandle ref) case vpiConstantSelect: return rfp->twid == 0; - case vpiLeftRange: rval += rfp->width; + case vpiLeftRange: + rval += rfp->width; case vpiRightRange: rval += vpi_get(vpiRightRange, rfp->parent) + PV_get_base(rfp); return rval; + case vpiAutomatic: + return vpi_get(vpiAutomatic, rfp->parent); + default: fprintf(stderr, "PV_get: property %d is unknown\n", code); } diff --git a/vvp/vpi_time.cc b/vvp/vpi_time.cc index 4c3a16833..23309f237 100644 --- a/vvp/vpi_time.cc +++ b/vvp/vpi_time.cc @@ -93,6 +93,9 @@ static int timevar_time_get(int code, vpiHandle ref) case vpiFuncType: return vpiTimeFunc; + case vpiAutomatic: + return 0; + default: fprintf(stderr, "Code: %d\n", code); assert(0); @@ -148,6 +151,9 @@ static int timevar_realtime_get(int code, vpiHandle ref) case vpiFuncType: return vpiRealFunc; + case vpiAutomatic: + return 0; + default: fprintf(stderr, "Code: %d\n", code); assert(0); diff --git a/vvp/vpip_bin.cc b/vvp/vpip_bin.cc index 0aadeac78..ecbcd9eb6 100644 --- a/vvp/vpip_bin.cc +++ b/vvp/vpip_bin.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2006 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-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,9 +16,6 @@ * 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: vpip_bin.cc,v 1.4 2006/08/03 05:05:06 steve Exp $" -#endif # include "config.h" # include "vpi_priv.h" @@ -31,69 +28,89 @@ #endif # include -void vpip_bin_str_to_vec4(vvp_vector4_t&vec4, - const char*buf, bool signed_flag) +void vpip_bin_str_to_vec4(vvp_vector4_t&vec4, const char*buf) { const char*ebuf = buf + strlen(buf); - vvp_bit4_t last = BIT4_0; - unsigned idx = 0; + unsigned skip_chars = 0; + const char*tbuf = buf; + /* Find the number of non-numeric characters. */ + while ((tbuf = strpbrk(tbuf, "-_"))) { + skip_chars += 1; + tbuf += 1; + } + vvp_vector4_t tval(strlen(buf)-skip_chars); while (ebuf > buf) { - vvp_bit4_t val; - - if (idx == vec4.size()) - break; - ebuf -= 1; - switch (*ebuf) { - case '0': val = BIT4_0; break; - case '1': val = BIT4_1; break; - case 'x': - case 'X': val = BIT4_X; break; - case 'z': - case 'Z': val = BIT4_Z; break; - default: val = BIT4_0; break; + /* Skip any "_" characters in the string. */ + while (*ebuf == '_') { + ebuf -= 1; + assert(ebuf > buf); + } + + /* If we find a "-" it must be at the head of the string. */ + if (*ebuf == '-') { + if (ebuf != buf) assert(0); + break; + } + + assert(idx < tval.size()); + switch (*ebuf) { + case '0': + tval.set_bit(idx, BIT4_0); + break; + case '1': + tval.set_bit(idx, BIT4_1); + break; + case 'x': + case 'X': + tval.set_bit(idx, BIT4_X); + break; + case 'z': + case 'Z': + tval.set_bit(idx, BIT4_Z); + break; + default: + /* Return "x" if there are invalid digits in the string. */ + fprintf(stderr, "Warning: Invalid binary digit %c(%d) in " + "\"%s\".\n", *ebuf, *ebuf, buf); + for (unsigned idx = 0 ; idx < vec4.size() ; idx += 1) { + vec4.set_bit(idx, BIT4_X); + } + return; + break; } - last = val; - vec4.set_bit(idx, val); idx += 1; } - /* Calculate the pad value based on the top bit and the signed - flag. We may sign extend or zero extend. */ - switch (last) { - case BIT4_0: - last = BIT4_0; + /* Make a negative value when needed. */ + if (buf[0] == '-') { + tval.invert(); + tval += (int64_t) 1; + } + + /* Find the correct padding value. */ + vvp_bit4_t pad; + switch (tval.value(tval.size()-1)) { + case BIT4_X: // Pad MSB 'x' with 'x' + pad = BIT4_X; break; - case BIT4_1: - last = signed_flag? BIT4_1 : BIT4_0; + case BIT4_Z: // Pad MSB 'z' with 'z' + pad = BIT4_Z; break; - case BIT4_X: - last = BIT4_X; - break; - case BIT4_Z: - last = BIT4_Z; + case BIT4_1: // If negative pad MSB '1' with '1' + if (buf[0] == '-') { + pad = BIT4_1; + break; + } + default: // Everything else gets '0' padded/ + pad = BIT4_0; break; } - while (idx < vec4.size()) - vec4.set_bit(idx++, last); + for (unsigned idx = 0 ; idx < vec4.size() ; idx += 1) { + if (idx < tval.size()) vec4.set_bit(idx, tval.value(idx)); + else vec4.set_bit(idx, pad); + } } - -/* - * $Log: vpip_bin.cc,v $ - * Revision 1.4 2006/08/03 05:05:06 steve - * Fix infinite loop padding binary string to result. - * - * Revision 1.3 2006/02/21 05:31:54 steve - * Put strings for reg objects. - * - * Revision 1.2 2002/08/12 01:35:09 steve - * conditional ident string using autoconfig. - * - * Revision 1.1 2002/05/11 04:39:35 steve - * Set and get memory words by string value. - * - */ - diff --git a/vvp/vpip_hex.cc b/vvp/vpip_hex.cc index 9c6a6a2e4..3846ac235 100644 --- a/vvp/vpip_hex.cc +++ b/vvp/vpip_hex.cc @@ -33,29 +33,30 @@ extern const char hex_digits[256]; void vpip_hex_str_to_vec4(vvp_vector4_t&val, const char*str) { unsigned str_len = strlen(str); - - char pad = '0'; - switch (str[0]) { - case 'x': - case 'X': - pad = 'x'; - break; - case 'z': - case 'Z': - pad = 'z'; - break; + unsigned skip_chars = 0; + const char*tstr = str; + /* Find the number of non-numeric characters. */ + while ((tstr = strpbrk(tstr, "-_"))) { + skip_chars += 1; + tstr += 1; } - - for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { + vvp_vector4_t tval(4*(str_len-skip_chars)); + skip_chars = 0; + for (unsigned idx = 0 ; idx < tval.size() ; idx += 1) { unsigned tmp; unsigned bit_off = idx%4; unsigned str_off = idx/4; - char ch; - if (str_off >= str_len) - ch = pad; - else - ch = str[str_len-str_off-1]; + + assert (str_off+skip_chars < str_len); + /* Skip any "_" characters in the string. */ + while((ch = str[str_len-str_off-1-skip_chars]) == '_') { + skip_chars += 1; + assert (str_off+skip_chars < str_len); + } + + /* If we find a "-" it must be at the head of the string. */ + if (ch == '-') assert(0); switch (ch) { case '0': @@ -69,7 +70,7 @@ void vpip_hex_str_to_vec4(vvp_vector4_t&val, const char*str) case '8': case '9': tmp = ch - '0'; - val.set_bit(idx, ((tmp>>bit_off)&1)? BIT4_1 : BIT4_0); + tval.set_bit(idx, ((tmp>>bit_off)&1)? BIT4_1 : BIT4_0); break; case 'a': case 'b': @@ -78,7 +79,7 @@ void vpip_hex_str_to_vec4(vvp_vector4_t&val, const char*str) case 'e': case 'f': tmp = ch - 'a' + 10; - val.set_bit(idx, ((tmp>>bit_off)&1)? BIT4_1 : BIT4_0); + tval.set_bit(idx, ((tmp>>bit_off)&1)? BIT4_1 : BIT4_0); break; case 'A': case 'B': @@ -87,22 +88,58 @@ void vpip_hex_str_to_vec4(vvp_vector4_t&val, const char*str) case 'E': case 'F': tmp = ch - 'A' + 10; - val.set_bit(idx, ((tmp>>bit_off)&1)? BIT4_1 : BIT4_0); + tval.set_bit(idx, ((tmp>>bit_off)&1)? BIT4_1 : BIT4_0); break; case 'x': case 'X': - val.set_bit(idx, BIT4_X); + tval.set_bit(idx, BIT4_X); break; case 'z': case 'Z': - val.set_bit(idx, BIT4_Z); + tval.set_bit(idx, BIT4_Z); break; default: - fprintf(stderr, "Unsupported digit %c(%d).\n", ch, ch); - assert(0); + /* Return "x" if there are invalid digits in the string. */ + fprintf(stderr, "Warning: Invalid hex digit %c(%d) in " + "\"%s\".\n", ch, ch, str); + for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { + val.set_bit(idx, BIT4_X); + } + return; break; } } + + /* Make a negative value when needed. */ + if (str[0] == '-') { + tval.invert(); + tval += (int64_t) 1; + } + + /* Find the correct padding value. */ + vvp_bit4_t pad; + switch (tval.value(tval.size()-1)) { + case BIT4_X: // Pad MSB 'x' with 'x'. + pad = BIT4_X; + break; + case BIT4_Z: // Pad MSB 'z' with 'z'. + pad = BIT4_Z; + break; + case BIT4_1: // If negative pad MSB '1' with '1'. + if (str[0] == '-') { + pad = BIT4_1; + break; + } + default: // Everything else gets '0' padded. + pad = BIT4_0; + break; + } + + /* Copy the temporary value to the real value, padding if needed. */ + for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { + if (idx < tval.size()) val.set_bit(idx, tval.value(idx)); + else val.set_bit(idx, pad); + } } void vpip_vec4_to_hex_str(const vvp_vector4_t&bits, char*buf, diff --git a/vvp/vpip_oct.cc b/vvp/vpip_oct.cc index f60e87b24..0b28e102e 100644 --- a/vvp/vpip_oct.cc +++ b/vvp/vpip_oct.cc @@ -33,29 +33,30 @@ extern const char oct_digits[64]; void vpip_oct_str_to_vec4(vvp_vector4_t&val, const char*str) { unsigned str_len = strlen(str); - - char pad = '0'; - switch (str[0]) { - case 'x': - case 'X': - pad = 'x'; - break; - case 'z': - case 'Z': - pad = 'z'; - break; + unsigned skip_chars = 0; + const char*tstr = str; + /* Find the number of non-numeric characters. */ + while ((tstr = strpbrk(tstr, "-_"))) { + skip_chars += 1; + tstr += 1; } - - for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { + vvp_vector4_t tval(3*(str_len-skip_chars)); + skip_chars = 0; + for (unsigned idx = 0 ; idx < tval.size() ; idx += 1) { unsigned tmp; unsigned bit_off = idx%3; unsigned str_off = idx/3; - char ch; - if (str_off >= str_len) - ch = pad; - else - ch = str[str_len-str_off-1]; + + assert(str_off+skip_chars < str_len); + /* Skip any "_" characters in the string. */ + while ((ch = str[str_len-str_off-1-skip_chars]) == '_') { + skip_chars += 1; + assert(str_off+skip_chars < str_len); + } + + /* If we find a "-" it must be at the head of the string. */ + if (ch == '-') assert(0); switch (ch) { case '0': @@ -67,22 +68,59 @@ void vpip_oct_str_to_vec4(vvp_vector4_t&val, const char*str) case '6': case '7': tmp = ch - '0'; - val.set_bit(idx, ((tmp>>bit_off)&1)? BIT4_1 : BIT4_0); + tval.set_bit(idx, ((tmp>>bit_off)&1)? BIT4_1 : BIT4_0); break; case 'x': case 'X': - val.set_bit(idx, BIT4_X); + tval.set_bit(idx, BIT4_X); break; case 'z': case 'Z': - val.set_bit(idx, BIT4_Z); + tval.set_bit(idx, BIT4_Z); break; default: - fprintf(stderr, "Unsupported digit %c(%d).\n", ch, ch); - assert(0); + /* Return "x" if there are invalid digits in the string. */ + fprintf(stderr, "Warning: Invalid octal digit %c(%d) in " + "\"%s\".\n", ch, ch, str); + for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { + val.set_bit(idx, BIT4_X); + } + return; break; } } + + /* Make a negative value when needed. */ + if (str[0] == '-') { + tval.invert(); + tval += (int64_t) 1; + } + + /* Find the correct padding value. */ + vvp_bit4_t pad; + switch (tval.value(tval.size()-1)) { + case BIT4_X: // Pad MSB 'x' with 'x' + pad = BIT4_X; + break; + case BIT4_Z: // Pad MSB 'z' with 'z' + pad = BIT4_Z; + break; + case BIT4_1: // If negative pad MSB '1' with '1' + if (str[0] == '-') { + pad = BIT4_1; + break; + } + default: // Everything else gets '0' padded. + pad = BIT4_0; + break; + } + + /* Copy the temporary value to the real value, padding if needed. */ + for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { + if (idx < tval.size()) val.set_bit(idx, tval.value(idx)); + else val.set_bit(idx, pad); + } + } void vpip_vec4_to_oct_str(const vvp_vector4_t&bits, char*buf, unsigned nbuf, diff --git a/vvp/vpip_to_dec.cc b/vvp/vpip_to_dec.cc index 602a8cf28..f59818845 100644 --- a/vvp/vpip_to_dec.cc +++ b/vvp/vpip_to_dec.cc @@ -220,26 +220,74 @@ unsigned vpip_vec4_to_dec_str(const vvp_vector4_t&vec4, return 0; } -void vpip_dec_str_to_vec4(vvp_vector4_t&vec, - const char*buf, bool signed_flag) +void vpip_dec_str_to_vec4(vvp_vector4_t&vec, const char*buf) { + /* Support for [xX]_*. */ + if (buf[0] == 'x' || buf[0] == 'X') { + for (unsigned idx = 0 ; idx < vec.size() ; idx += 1) { + vec.set_bit(idx, BIT4_X); + } + const char*tbuf = buf+1; + /* See if this is a valid constant. */ + while (*tbuf) { + if (*tbuf != '_') { + fprintf(stderr, "Warning: Invalid decimal \"x\" " + "value \"%s\".\n", buf); + return; + } + tbuf += 1; + } + return; + } + + /* Support for [zZ]_*. */ + if (buf[0] == 'z' || buf[0] == 'Z') { + const char*tbuf = buf+1; + /* See if this is a valid constant, if not return "x". */ + while (*tbuf) { + if (*tbuf != '_') { + fprintf(stderr, "Warning: Invalid decimal \"z\" " + "value \"%s\".\n", buf); + for (unsigned idx = 0 ; idx < vec.size() ; idx += 1) { + vec.set_bit(idx, BIT4_X); + } + return; + } + tbuf += 1; + } + for (unsigned idx = 0 ; idx < vec.size() ; idx += 1) { + vec.set_bit(idx, BIT4_Z); + } + return; + } + /* The str string is the decimal value with the least significant digit first. This loop creates that string by reversing the order of the buf string. For example, if the input is "1234", str gets "4321". */ unsigned slen = strlen(buf); char*str = new char[slen + 1]; - int is_negative = 0; + bool is_negative = false; for (unsigned idx = 0 ; idx < slen ; idx += 1) { if (idx == slen-1 && buf[slen-idx-1] == '-') { - is_negative = 1; + is_negative = true; slen--; continue; } + while (buf[slen-idx-1] == '_') { + slen--; + } if (isdigit(buf[slen-idx-1])) str[idx] = buf[slen-idx-1]; - else - str[idx] = '0'; + else { + /* Return "x" if there are invalid digits in the string. */ + fprintf(stderr, "Warning: Invalid decimal digit %c(%d) in " + "\"%s.\"\n", buf[slen-idx-1], buf[slen-idx-1], buf); + for (unsigned idx = 0 ; idx < vec.size() ; idx += 1) { + vec.set_bit(idx, BIT4_X); + } + return; + } } str[slen] = 0; @@ -274,7 +322,7 @@ void vpip_dec_str_to_vec4(vvp_vector4_t&vec, if (is_negative) { vec.invert(); - vec += 1; + vec += (int64_t) 1; } delete[]str; diff --git a/vvp/vthread.cc b/vvp/vthread.cc index cab1c9c1d..ddeda1c11 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -2730,14 +2730,18 @@ bool of_JOIN(vthread_t thr, vvp_code_t cp) assert(thr->fork_count > 0); - if (thr->wt_context != thr->rd_context) { - /* Pop the child context from the write context stack. */ - vvp_context_t child_context = thr->wt_context; - thr->wt_context = vvp_get_stacked_context(child_context); + /* If the child thread is in an automatic scope... */ + if (thr->child->wt_context) { + /* and is the top level task/function thread... */ + if (thr->wt_context != thr->rd_context) { + /* Pop the child context from the write context stack. */ + vvp_context_t child_context = thr->wt_context; + thr->wt_context = vvp_get_stacked_context(child_context); - /* Push the child context onto the read context stack */ - vvp_set_stacked_context(child_context, thr->rd_context); - thr->rd_context = child_context; + /* Push the child context onto the read context stack */ + vvp_set_stacked_context(child_context, thr->rd_context); + thr->rd_context = child_context; + } } /* If the child has already ended, reap it now. */