Add support for SV do/while

This commit is contained in:
Cary R 2013-09-16 20:01:06 -07:00
parent 8412d0d55f
commit d8f945be23
23 changed files with 323 additions and 48 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2008,2010,2012-2013 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2013 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
@ -247,6 +247,17 @@ PDisable::~PDisable()
{
}
PDoWhile::PDoWhile(PExpr*ex, Statement*st)
: cond_(ex), statement_(st)
{
}
PDoWhile::~PDoWhile()
{
delete cond_;
delete statement_;
}
PEventStatement::PEventStatement(const svector<PEEvent*>&ee)
: expr_(ee), statement_(0)
{
@ -360,8 +371,8 @@ PTrigger::~PTrigger()
{
}
PWhile::PWhile(PExpr*e1, Statement*st)
: cond_(e1), statement_(st)
PWhile::PWhile(PExpr*ex, Statement*st)
: cond_(ex), statement_(st)
{
}

View File

@ -336,6 +336,22 @@ class PDisable : public Statement {
pform_name_t scope_;
};
class PDoWhile : public Statement {
public:
PDoWhile(PExpr*ex, Statement*st);
~PDoWhile();
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;
virtual void dump(ostream&out, unsigned ind) const;
private:
PExpr*cond_;
Statement*statement_;
};
/*
* The event statement represents the event delay in behavioral
* code. It comes from such things as:
@ -499,7 +515,7 @@ class PTrigger : public Statement {
class PWhile : public Statement {
public:
PWhile(PExpr*e1, Statement*st);
PWhile(PExpr*ex, Statement*st);
~PWhile();
virtual NetProc* elaborate(Design*des, NetScope*scope) const;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2012 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2013 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
@ -1030,6 +1030,13 @@ void NetDisable::dump(ostream&o, unsigned ind) const
<< "/* " << get_fileline() << " */" << endl;
}
void NetDoWhile::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "do" << endl;
proc_->dump(o, ind+3);
o << setw(ind) << "" << "while (" << *cond_ << ");" << endl;
}
void NetEvProbe::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "";

View File

@ -1795,6 +1795,17 @@ void PDelayStatement::elaborate_scope(Design*des, NetScope*scope) const
statement_ -> elaborate_scope(des, scope);
}
/*
* Statements that contain a further statement but do not
* intrinsically add a scope need to elaborate_scope the contained
* statement.
*/
void PDoWhile::elaborate_scope(Design*des, NetScope*scope) const
{
if (statement_)
statement_ -> elaborate_scope(des, scope);
}
/*
* Statements that contain a further statement but do not
* intrinsically add a scope need to elaborate_scope the contained

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2012 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2012 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
@ -755,6 +755,12 @@ void PDelayStatement::elaborate_sig(Design*des, NetScope*scope) const
statement_->elaborate_sig(des, scope);
}
void PDoWhile::elaborate_sig(Design*des, NetScope*scope) const
{
if (statement_)
statement_->elaborate_sig(des, scope);
}
void PEventStatement::elaborate_sig(Design*des, NetScope*scope) const
{
if (statement_)

View File

@ -3718,6 +3718,18 @@ NetProc* PDisable::elaborate(Design*des, NetScope*scope) const
return obj;
}
/*
* The do/while loop is fairly directly represented in the netlist.
*/
NetProc* PDoWhile::elaborate(Design*des, NetScope*scope) const
{
NetExpr*tmp = elab_and_eval(des, scope, cond_, -1);
tmp->set_line(*this);
NetDoWhile*loop = new NetDoWhile(tmp, statement_->elaborate(des, scope));
loop->set_line(*this);
return loop;
}
/*
* An event statement is an event delay of some sort, attached to a
* statement. Some Verilog examples are:

23
emit.cc
View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2013 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
@ -261,6 +261,17 @@ bool NetDisable::emit_proc(struct target_t*tgt) const
return tgt->proc_disable(this);
}
bool NetDoWhile::emit_proc(struct target_t*tgt) const
{
tgt->proc_do_while(this);
return true;
}
void NetDoWhile::emit_proc_recurse(struct target_t*tgt) const
{
proc_->emit_proc(tgt);
}
bool NetForce::emit_proc(struct target_t*tgt) const
{
return tgt->proc_force(this);
@ -318,6 +329,11 @@ bool NetWhile::emit_proc(struct target_t*tgt) const
return true;
}
void NetWhile::emit_proc_recurse(struct target_t*tgt) const
{
proc_->emit_proc(tgt);
}
void NetBlock::emit_recurse(struct target_t*tgt) const
{
if (last_ == 0)
@ -459,11 +475,6 @@ bool NetScope::emit_defs(struct target_t*tgt) const
return flag;
}
void NetWhile::emit_proc_recurse(struct target_t*tgt) const
{
proc_->emit_proc(tgt);
}
int Design::emit(struct target_t*tgt) const
{
int rc = 0;

View File

@ -402,6 +402,7 @@ typedef enum ivl_statement_type_e {
IVL_ST_DELAY = 11,
IVL_ST_DELAYX = 12,
IVL_ST_DISABLE = 13,
IVL_ST_DO_WHILE = 30,
IVL_ST_FORCE = 14,
IVL_ST_FOREVER = 15,
IVL_ST_FORK = 16,

View File

@ -562,6 +562,49 @@ bool NetDisable::evaluate_function(const LineInfo&,
return true;
}
bool NetDoWhile::evaluate_function(const LineInfo&loc,
map<perm_string,LocalVar>&context_map) const
{
bool flag = true;
if (debug_eval_tree) {
cerr << get_fileline() << ": NetDoWhile::evaluate_function: "
<< "Start loop" << endl;
}
while (!disable) {
// Evaluate the statement.
flag = proc_->evaluate_function(loc, context_map);
if (! flag)
break;
// Evaluate the condition expression to try and get the
// condition for the loop.
NetExpr*cond = cond_->evaluate_function(loc, context_map);
if (cond == 0) {
flag = false;
break;
}
NetEConst*cond_const = dynamic_cast<NetEConst*> (cond);
ivl_assert(loc, cond_const);
long val = cond_const->value().as_long();
delete cond;
// If the condition is false, then the loop is done.
if (val == 0)
break;
}
if (debug_eval_tree) {
cerr << get_fileline() << ": NetDoWhile::evaluate_function: "
<< "Done loop, flag=" << (flag?"true":"false") << endl;
}
return flag;
}
bool NetForever::evaluate_function(const LineInfo&loc,
map<perm_string,LocalVar>&context_map) const
{

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2012 Stephen Williams (steve@icarus.com)
* Copyright (c) 2002-2013 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
@ -374,6 +374,15 @@ NexusSet* NetCondit::nex_input(bool rem_out)
return result;
}
NexusSet* NetDoWhile::nex_input(bool rem_out)
{
NexusSet*result = proc_->nex_input(rem_out);
NexusSet*tmp = cond_->nex_input(rem_out);
result->add(*tmp);
delete tmp;
return result;
}
NexusSet* NetForce::nex_input(bool)
{
cerr << get_fileline() << ": internal warning: NetForce::nex_input()"

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2002-2013 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
@ -117,6 +117,12 @@ void NetCondit::nex_output(NexusSet&out)
else_->nex_output(out);
}
void NetDoWhile::nex_output(NexusSet&out)
{
if (proc_ != 0)
proc_->nex_output(out);
}
void NetEvWait::nex_output(NexusSet&out)
{
assert(statement_);

View File

@ -2810,6 +2810,14 @@ DelayType NetCondit::delay_type() const
return combine_delays(if_type, el_type);
}
/*
* A do/while will execute the body at least once.
*/
DelayType NetDoWhile::delay_type() const
{
return proc_->delay_type();
}
DelayType NetEvWait::delay_type() const
{
return DEFINITE_DELAY;

View File

@ -2913,6 +2913,34 @@ class NetDisable : public NetProc {
NetDisable& operator= (const NetDisable&);
};
/*
* The do/while statement is a condition that is tested at the end of
* each iteration, and a statement (a NetProc) that is executed once and
* then again as long as the condition is true.
*/
class NetDoWhile : public NetProc {
public:
NetDoWhile(NetExpr*c, NetProc*p)
: cond_(c), proc_(p) { }
const NetExpr*expr() const { return cond_; }
void emit_proc_recurse(struct target_t*) const;
virtual NexusSet* nex_input(bool rem_out = true);
virtual void nex_output(NexusSet&);
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type() const;
virtual bool evaluate_function(const LineInfo&loc,
map<perm_string,LocalVar>&ctx) const;
private:
NetExpr* cond_;
NetProc*proc_;
};
/*
* A NetEvent is an object that represents an event object, that is
* objects declared like so in Verilog:

11
parse.y
View File

@ -1289,6 +1289,12 @@ loop_statement /* IEEE1800-2005: A.6.8 */
$$ = tmp;
}
| K_do statement_or_null K_while '(' expression ')' ';'
{ PDoWhile*tmp = new PDoWhile($5, $2);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| K_foreach '(' IDENTIFIER '[' loop_variables ']' ')' statement_or_null
{ yyerror(@1, "sorry: foreach loops not supported");
delete[]$3;
@ -1321,6 +1327,11 @@ loop_statement /* IEEE1800-2005: A.6.8 */
yyerror(@1, "error: Error in while loop condition.");
}
| K_do statement_or_null K_while '(' error ')' ';'
{ $$ = 0;
yyerror(@1, "error: Error in do/while loop condition.");
}
| K_foreach '(' IDENTIFIER '[' error ']' ')' statement_or_null
{ $$ = 0;
yyerror(@4, "error: Errors in foreach loop variables list.");

View File

@ -840,6 +840,13 @@ void PDisable::dump(ostream&out, unsigned ind) const
<< get_fileline() << " */" << endl;
}
void PDoWhile::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "do" << endl;
statement_->dump(out, ind+3);
out << setw(ind) << "" << "while (" << *cond_ << ");" << endl;
}
void PEventStatement::dump(ostream&out, unsigned ind) const
{
if (expr_.count() == 0) {

View File

@ -2557,6 +2557,7 @@ extern "C" ivl_expr_t ivl_stmt_cond_expr(ivl_statement_t net)
case IVL_ST_CASEZ:
return net->u_.case_.cond;
case IVL_ST_DO_WHILE:
case IVL_ST_REPEAT:
case IVL_ST_WHILE:
return net->u_.while_.cond_;
@ -2819,6 +2820,7 @@ extern "C" ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net)
return net->u_.forever_.stmt_;
case IVL_ST_WAIT:
return net->u_.wait_.stmt_;
case IVL_ST_DO_WHILE:
case IVL_ST_REPEAT:
case IVL_ST_WHILE:
return net->u_.while_.stmt_;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2012 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-2013 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
@ -618,6 +618,31 @@ bool dll_target::proc_disable(const NetDisable*net)
return true;
}
void dll_target::proc_do_while(const NetDoWhile*net)
{
assert(stmt_cur_);
assert(stmt_cur_->type_ == IVL_ST_NONE);
FILE_NAME(stmt_cur_, net);
stmt_cur_->type_ = IVL_ST_DO_WHILE;
stmt_cur_->u_.while_.stmt_ = (struct ivl_statement_s*)
calloc(1, sizeof(struct ivl_statement_s));
assert(expr_ == 0);
net->expr()->expr_scan(this);
stmt_cur_->u_.while_.cond_ = expr_;
expr_ = 0;
/* Now generate the statement of the do/while loop. We know it is
a single statement, and we know that the
emit_proc_recurse() will call emit_proc() for it. */
ivl_statement_t save_cur_ = stmt_cur_;
stmt_cur_ = save_cur_->u_.while_.stmt_;
net->emit_proc_recurse(this);
stmt_cur_ = save_cur_;
}
bool dll_target::proc_force(const NetForce*net)
{

View File

@ -118,6 +118,7 @@ struct dll_target : public target_t, public expr_scan_t {
bool proc_deassign(const NetDeassign*);
bool proc_delay(const NetPDelay*);
bool proc_disable(const NetDisable*);
void proc_do_while(const NetDoWhile*);
bool proc_force(const NetForce*);
void proc_forever(const NetForever*);
void proc_free(const NetFree*);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2011 Stephen Williams <steve@icarus.com>
* Copyright (c) 1998-2013 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
@ -364,6 +364,13 @@ bool target_t::proc_disable(const NetDisable*obj)
return false;
}
void target_t::proc_do_while(const NetDoWhile*net)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled do/while:" << endl;
net->dump(cerr, 6);
}
bool target_t::proc_force(const NetForce*)
{
cerr << "target (" << typeid(*this).name() << "): "

View File

@ -1,7 +1,7 @@
#ifndef __target_H
#define __target_H
/*
* Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2013 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
@ -130,6 +130,7 @@ struct target_t {
virtual bool proc_deassign(const NetDeassign*);
virtual bool proc_delay(const NetPDelay*);
virtual bool proc_disable(const NetDisable*);
virtual void proc_do_while(const NetDoWhile*);
virtual bool proc_force(const NetForce*);
virtual void proc_forever(const NetForever*);
virtual void proc_free(const NetFree*);

View File

@ -388,6 +388,13 @@ void show_statement(ivl_statement_t net, unsigned ind)
show_stmt_disable(net, ind);
break;
case IVL_ST_DO_WHILE:
fprintf(out, "%*sdo\n", ind, "");
show_statement(ivl_stmt_sub_stmt(net), ind+2);
fprintf(out, "%*swhile\n", ind, "");
show_expression(ivl_stmt_cond_expr(net), ind+4);
break;
case IVL_ST_FORCE:
show_stmt_force(net, ind);
break;

View File

@ -1269,6 +1269,13 @@ void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt)
case IVL_ST_DISABLE:
emit_stmt_disable(scope, stmt);
break;
case IVL_ST_DO_WHILE:
fprintf(stderr, "%s:%u: vlog95 sorry: do/while is not "
"currently translated.\n",
ivl_stmt_file(stmt),
ivl_stmt_lineno(stmt));
vlog_errors += 1;
break;
case IVL_ST_FORCE:
emit_stmt_force(scope, stmt);
break;

View File

@ -1334,6 +1334,71 @@ static int show_stmt_disable(ivl_statement_t net, ivl_scope_t sscope)
return rc;
}
static struct vector_info reduction_or(struct vector_info cvec)
{
struct vector_info result;
switch (cvec.base) {
case 0:
result.base = 0;
result.wid = 1;
break;
case 1:
result.base = 1;
result.wid = 1;
break;
case 2:
case 3:
result.base = 0;
result.wid = 1;
break;
default:
clr_vector(cvec);
result.base = allocate_vector(1);
result.wid = 1;
assert(result.base);
fprintf(vvp_out, " %%or/r %u, %u, %u;\n", result.base,
cvec.base, cvec.wid);
break;
}
return result;
}
static int show_stmt_do_while(ivl_statement_t net, ivl_scope_t sscope)
{
int rc = 0;
struct vector_info cvec;
unsigned top_label = local_count++;
show_stmt_file_line(net, "Do/While statement.");
/* Start the loop. The top of the loop starts a basic block
because it can be entered from above or from the bottom of
the loop. */
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, top_label);
clear_expression_lookaside();
/* Draw the body of the loop. */
rc += show_statement(ivl_stmt_sub_stmt(net), sscope);
/* Draw the evaluation of the condition expression, and test
the result. If the expression evaluates to true, then
branch to the top label. */
cvec = draw_eval_expr(ivl_stmt_cond_expr(net), STUFF_OK_XZ|STUFF_OK_47);
if (cvec.wid > 1)
cvec = reduction_or(cvec);
fprintf(vvp_out, " %%jmp/1 T_%u.%u, %u;\n",
thread_count, top_label, cvec.base);
if (cvec.base >= 8)
clr_vector(cvec);
clear_expression_lookaside();
return rc;
}
static int show_stmt_force(ivl_statement_t net)
{
ivl_expr_t rval;
@ -1645,37 +1710,6 @@ static int show_stmt_wait(ivl_statement_t net, ivl_scope_t sscope)
return show_statement(ivl_stmt_sub_stmt(net), sscope);
}
static struct vector_info reduction_or(struct vector_info cvec)
{
struct vector_info result;
switch (cvec.base) {
case 0:
result.base = 0;
result.wid = 1;
break;
case 1:
result.base = 1;
result.wid = 1;
break;
case 2:
case 3:
result.base = 0;
result.wid = 1;
break;
default:
clr_vector(cvec);
result.base = allocate_vector(1);
result.wid = 1;
assert(result.base);
fprintf(vvp_out, " %%or/r %u, %u, %u;\n", result.base,
cvec.base, cvec.wid);
break;
}
return result;
}
static int show_stmt_while(ivl_statement_t net, ivl_scope_t sscope)
{
int rc = 0;
@ -2184,6 +2218,10 @@ static int show_statement(ivl_statement_t net, ivl_scope_t sscope)
rc += show_stmt_disable(net, sscope);
break;
case IVL_ST_DO_WHILE:
rc += show_stmt_do_while(net, sscope);
break;
case IVL_ST_FORCE:
rc += show_stmt_force(net);
break;