From 7beb059d90bc4b465db4fa00ed775c62f71b2a69 Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 3 Sep 2008 16:05:12 -0700 Subject: [PATCH] Add blocking repeat event control, make repeat sign aware This patch adds blocking repeat event controls and also makes the base repeat statement sign aware. If the argument to repeat is negative (it must be a signed variable) then this is treated just like an argument of 0 (there is no looping). Doing this allows us to model the repeat event control as follows. lhs = repeat(count) @(event) rhs; is translated to: begin temp = rhs; repeat (count) @(event); lhs = temp; end This patch also pushes the non-blocking event control information to the elaboration phase where it will report they are not currently supported. --- Statement.cc | 57 +++++------------------- Statement.h | 11 ++++- elaborate.cc | 100 +++++++++++++++++++++++++++++++++++------- parse.y | 13 ++---- pform_dump.cc | 39 +++++++++++++--- tgt-vvp/vvp_process.c | 5 ++- 6 files changed, 144 insertions(+), 81 deletions(-) diff --git a/Statement.cc b/Statement.cc index 02680d322..a8c9b9627 100644 --- a/Statement.cc +++ b/Statement.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-1999 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-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: Statement.cc,v 1.30 2007/05/24 04:07:11 steve Exp $" -#endif # include "config.h" @@ -30,19 +27,19 @@ Statement::~Statement() } PAssign_::PAssign_(PExpr*lval, PExpr*ex) -: event_(0), lval_(lval), rval_(ex) +: event_(0), count_(0), lval_(lval), rval_(ex) { delay_ = 0; } PAssign_::PAssign_(PExpr*lval, PExpr*de, PExpr*ex) -: event_(0), lval_(lval), rval_(ex) +: event_(0), count_(0), lval_(lval), rval_(ex) { delay_ = de; } -PAssign_::PAssign_(PExpr*lval, PEventStatement*ev, PExpr*ex) -: event_(ev), lval_(lval), rval_(ex) +PAssign_::PAssign_(PExpr*lval, PExpr*cnt, PEventStatement*ev, PExpr*ex) +: event_(ev), count_(cnt), lval_(lval), rval_(ex) { delay_ = 0; } @@ -63,8 +60,8 @@ PAssign::PAssign(PExpr*lval, PExpr*d, PExpr*ex) { } -PAssign::PAssign(PExpr*lval, PEventStatement*d, PExpr*ex) -: PAssign_(lval, d, ex) +PAssign::PAssign(PExpr*lval, PExpr*cnt, PEventStatement*d, PExpr*ex) +: PAssign_(lval, cnt, d, ex) { } @@ -82,6 +79,11 @@ PAssignNB::PAssignNB(PExpr*lval, PExpr*d, PExpr*ex) { } +PAssignNB::PAssignNB(PExpr*lval, PExpr*cnt, PEventStatement*d, PExpr*ex) +: PAssign_(lval, cnt, d, ex) +{ +} + PAssignNB::~PAssignNB() { } @@ -298,38 +300,3 @@ PWhile::~PWhile() delete cond_; delete statement_; } - -/* - * $Log: Statement.cc,v $ - * Revision 1.30 2007/05/24 04:07:11 steve - * Rework the heirarchical identifier parse syntax and pform - * to handle more general combinations of heirarch and bit selects. - * - * Revision 1.29 2004/02/18 17:11:54 steve - * Use perm_strings for named langiage items. - * - * Revision 1.28 2002/08/12 01:34:58 steve - * conditional ident string using autoconfig. - * - * Revision 1.27 2002/04/21 22:31:02 steve - * Redo handling of assignment internal delays. - * Leave it possible for them to be calculated - * at run time. - * - * Revision 1.26 2002/04/21 04:59:07 steve - * Add support for conbinational events by finding - * the inputs to expressions and some statements. - * Get case and assignment statements working. - * - * Revision 1.25 2001/12/03 04:47:14 steve - * Parser and pform use hierarchical names as hname_t - * objects instead of encoded strings. - * - * Revision 1.24 2001/11/22 06:20:59 steve - * Use NetScope instead of string for scope path. - * - * Revision 1.23 2001/07/25 03:10:48 steve - * Create a config.h.in file to hold all the config - * junk, and support gcc 3.0. (Stephan Boettcher) - */ - diff --git a/Statement.h b/Statement.h index 5bca41739..bcc033937 100644 --- a/Statement.h +++ b/Statement.h @@ -93,7 +93,7 @@ class PAssign_ : public Statement { public: explicit PAssign_(PExpr*lval, PExpr*ex); explicit PAssign_(PExpr*lval, PExpr*de, PExpr*ex); - explicit PAssign_(PExpr*lval, PEventStatement*de, PExpr*ex); + explicit PAssign_(PExpr*lval, PExpr*cnt, PEventStatement*de, PExpr*ex); virtual ~PAssign_() =0; const PExpr* lval() const { return lval_; } @@ -104,6 +104,7 @@ class PAssign_ : public Statement { PExpr* delay_; PEventStatement*event_; + PExpr* count_; private: PExpr* lval_; @@ -115,7 +116,7 @@ class PAssign : public PAssign_ { public: explicit PAssign(PExpr*lval, PExpr*ex); explicit PAssign(PExpr*lval, PExpr*de, PExpr*ex); - explicit PAssign(PExpr*lval, PEventStatement*de, PExpr*ex); + explicit PAssign(PExpr*lval, PExpr*cnt, PEventStatement*de, PExpr*ex); ~PAssign(); virtual void dump(ostream&out, unsigned ind) const; @@ -129,6 +130,7 @@ class PAssignNB : public PAssign_ { public: explicit PAssignNB(PExpr*lval, PExpr*ex); explicit PAssignNB(PExpr*lval, PExpr*de, PExpr*ex); + explicit PAssignNB(PExpr*lval, PExpr*cnt, PEventStatement*de, PExpr*ex); ~PAssignNB(); virtual void dump(ostream&out, unsigned ind) const; @@ -333,6 +335,9 @@ class PEventStatement : public Statement { void set_statement(Statement*st); virtual void dump(ostream&out, unsigned ind) const; + // Call this with a NULL statement only. It is used to print + // the event expression for inter-assignment event controls. + virtual void dump_inline(ostream&out) const; virtual NetProc* elaborate(Design*des, NetScope*scope) const; virtual void elaborate_scope(Design*des, NetScope*scope) const; virtual void elaborate_sig(Design*des, NetScope*scope) const; @@ -348,6 +353,8 @@ class PEventStatement : public Statement { Statement*statement_; }; +ostream& operator << (ostream&o, const PEventStatement&obj); + class PForce : public Statement { public: diff --git a/elaborate.cc b/elaborate.cc index f2927719e..e693f45d5 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1803,6 +1803,7 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const if (rv == 0) return 0; assert(rv); + if (count_) assert(event_); /* Rewrite delayed assignments as assignments that are delayed. For example, a = # b; becomes: @@ -1855,19 +1856,58 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const /* Generate the delay statement with the final assignment attached to it. If this is an event delay, elaborate the PEventStatement. Otherwise, create the - right NetPDelay object. */ + right NetPDelay object. For a repeat event control + repeat the event and then do the final assignment. */ NetProc*st; if (event_) { - st = event_->elaborate_st(des, scope, a2); - if (st == 0) { - cerr << event_->get_fileline() << ": error: " - "unable to elaborate event expression." - << endl; - des->errors += 1; - return 0; - } - assert(st); + if (count_) { + NetExpr*count = elab_and_eval(des, scope, count_, -1); + if (count == 0) { + cerr << get_fileline() << ": Unable to " + "elaborate repeat expression." << endl; + des->errors += 1; + return 0; + } + st = event_->elaborate(des, scope); + if (st == 0) { + cerr << event_->get_fileline() << ": error: " + "unable to elaborate event expression." + << endl; + des->errors += 1; + return 0; + } + // If the expression is a constant, handle + // certain special iteration counts. + if (NetEConst*ce = dynamic_cast(count)) { + long val = ce->value().as_long(); + // We only need the real statement. + if (val <= 0) { + delete count; + delete st; + st = 0; + + // We don't need the repeat statement. + } else if (val == 1) { + delete count; + + // We need a repeat statement. + } else { + st = new NetRepeat(count, st); + } + } else { + st = new NetRepeat(count, st); + } + } else { + st = event_->elaborate_st(des, scope, a2); + if (st == 0) { + cerr << event_->get_fileline() << ": error: " + "unable to elaborate event expression." + << endl; + des->errors += 1; + return 0; + } + } } else { NetPDelay*de = new NetPDelay(delay, a2); de->set_line(*this); @@ -1877,7 +1917,8 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const /* And build up the complex statement. */ NetBlock*bl = new NetBlock(NetBlock::SEQU, 0); bl->append(a1); - bl->append(st); + if (st) bl->append(st); + if (count_) bl->append(a2); return bl; } @@ -1948,6 +1989,34 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const if (delay_ != 0) delay = elaborate_delay_expr(delay_, des, scope); + if (count_ != 0 || event_ != 0) { + NetExpr*count = 0; + if (count_ != 0) { + assert(event_ != 0); + count = elab_and_eval(des, scope, count_, -1); + if (count == 0) { + cerr << get_fileline() << ": Unable to elaborate " + "repeat expression." << endl; + des->errors += 1; +// return 0; + } + } + + NetProc* event = event_->elaborate(des, scope); + if (event == 0) { + cerr << get_fileline() << ": unable to elaborate " + "event expression." << endl; + des->errors += 1; +// return 0; + } + + cerr << get_fileline() << ": sorry: non blocking "; + if (count_) cerr << "repeat "; + cerr << "event controls are not supported." << endl; + des->errors += 1; + return 0; + } + /* All done with this node. Mark its line number and check it in. */ NetAssignNB*cur = new NetAssignNB(lv, rv); cur->set_delay(delay); @@ -3195,17 +3264,14 @@ NetProc* PRepeat::elaborate(Design*des, NetScope*scope) const // If the expression is a constant, handle certain special // iteration counts. if (NetEConst*ce = dynamic_cast(expr)) { - verinum val = ce->value(); - switch (val.as_ulong()) { - case 0: + long val = ce->value().as_long(); + if (val <= 0) { delete expr; delete stat; return new NetBlock(NetBlock::SEQU, 0); - case 1: + } else if (val == 1) { delete expr; return stat; - default: - break; } } diff --git a/parse.y b/parse.y index 015034559..4f02bafc7 100644 --- a/parse.y +++ b/parse.y @@ -3648,28 +3648,23 @@ statement $$ = tmp; } | lpvalue '=' event_control expression ';' - { PAssign*tmp = new PAssign($1,$3,$4); + { PAssign*tmp = new PAssign($1,0,$3,$4); FILE_NAME(tmp, @1); $$ = tmp; } | lpvalue '=' K_repeat '(' expression ')' event_control expression ';' - { PAssign*tmp = new PAssign($1,$7,$8); + { PAssign*tmp = new PAssign($1,$5,$7,$8); FILE_NAME(tmp,@1); tmp->set_lineno(@1.first_line); - yyerror(@3, "sorry: repeat event control not supported."); - delete $5; $$ = tmp; } | lpvalue K_LE event_control expression ';' - { yyerror(@1, "sorry: Event controls not supported here."); - PAssignNB*tmp = new PAssignNB($1,$4); + { PAssignNB*tmp = new PAssignNB($1,0,$3,$4); FILE_NAME(tmp, @1); $$ = tmp; } | lpvalue K_LE K_repeat '(' expression ')' event_control expression ';' - { yyerror(@1, "sorry: Event controls not supported here."); - delete $5; - PAssignNB*tmp = new PAssignNB($1,$8); + { PAssignNB*tmp = new PAssignNB($1,$5,$7,$8); FILE_NAME(tmp, @1); $$ = tmp; } diff --git a/pform_dump.cc b/pform_dump.cc index 2d3cc5fd1..cb35237e8 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -40,6 +40,12 @@ ostream& operator << (ostream&out, const PExpr&obj) return out; } +ostream& operator << (ostream&out, const PEventStatement&obj) +{ + obj.dump_inline(out); + return out; +} + ostream& operator << (ostream&o, const PDelays&d) { d.dump_delays(o); @@ -554,16 +560,20 @@ void AContrib::dump(ostream&out, unsigned ind) const void PAssign::dump(ostream&out, unsigned ind) const { - out << setw(ind) << ""; - out << *lval() << " = " << delay_ << " " << *rval() << ";"; - out << " /* " << get_fileline() << " */" << endl; + out << setw(ind) << "" << *lval() << " = "; + if (delay_) out << "#" << *delay_ << " "; + if (count_) out << "repeat(" << *count_ << ") "; + if (event_) out << *event_ << " "; + out << *rval() << ";" << " /* " << get_fileline() << " */" << endl; } void PAssignNB::dump(ostream&out, unsigned ind) const { - out << setw(ind) << ""; - out << *lval() << " <= " << delay_ << " " << *rval() << ";"; - out << " /* " << get_fileline() << " */" << endl; + out << setw(ind) << "" << *lval() << " <= "; + if (delay_) out << "#" << *delay_ << " "; + if (count_) out << "repeat(" << *count_ << ") "; + if (event_) out << *event_ << " "; + out << *rval() << ";" << " /* " << get_fileline() << " */" << endl; } void PBlock::dump(ostream&out, unsigned ind) const @@ -713,6 +723,23 @@ void PEventStatement::dump(ostream&out, unsigned ind) const } } +void PEventStatement::dump_inline(ostream&out) const +{ + assert(statement_ == 0); + + if (expr_.count() == 0) { + out << "@* "; + + } else { + out << "@(" << *(expr_[0]); + if (expr_.count() > 1) + for (unsigned idx = 1 ; idx < expr_.count() ; idx += 1) + out << " or " << *(expr_[idx]); + + out << ")"; + } +} + void PForce::dump(ostream&out, unsigned ind) const { out << setw(ind) << "" << "force " << *lval_ << " = " << *expr_ diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 41220c832..302c1e3c4 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -1402,10 +1402,11 @@ static int show_stmt_repeat(ivl_statement_t net, ivl_scope_t sscope) unsigned lab_top = local_count++, lab_out = local_count++; ivl_expr_t exp = ivl_stmt_cond_expr(net); struct vector_info cnt = draw_eval_expr(exp, 0); + char *sign = ivl_expr_signed(exp) ? "s" : "u"; /* Test that 0 < expr */ - fprintf(vvp_out, "T_%u.%u %%cmp/u 0, %u, %u;\n", thread_count, - lab_top, cnt.base, cnt.wid); + fprintf(vvp_out, "T_%u.%u %%cmp/%s 0, %u, %u;\n", thread_count, + lab_top, sign, cnt.base, cnt.wid); clear_expression_lookaside(); fprintf(vvp_out, " %%jmp/0xz T_%u.%u, 5;\n", thread_count, lab_out); /* This adds -1 (all ones in 2's complement) to the count. */