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.
This commit is contained in:
Cary R 2008-09-03 16:05:12 -07:00 committed by Stephen Williams
parent 60169f6353
commit 7beb059d90
6 changed files with 144 additions and 81 deletions

View File

@ -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)
*/

View File

@ -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:

View File

@ -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 = #<d> b; becomes:
@ -1855,9 +1856,49 @@ 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_) {
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<NetEConst*>(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: "
@ -1866,8 +1907,7 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
des->errors += 1;
return 0;
}
assert(st);
}
} 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<NetEConst*>(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;
}
}

13
parse.y
View File

@ -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;
}

View File

@ -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_

View File

@ -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. */