Add support for wait fork to the compiler and code generators
This commit is contained in:
parent
61fbfb562e
commit
97d06b107f
|
|
@ -391,6 +391,7 @@ class PEventStatement : public Statement {
|
||||||
NetProc* elaborate_st(Design*des, NetScope*scope, NetProc*st) const;
|
NetProc* elaborate_st(Design*des, NetScope*scope, NetProc*st) const;
|
||||||
|
|
||||||
NetProc* elaborate_wait(Design*des, NetScope*scope, NetProc*st) const;
|
NetProc* elaborate_wait(Design*des, NetScope*scope, NetProc*st) const;
|
||||||
|
NetProc* elaborate_wait_fork(Design*des, NetScope*scope) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
svector<PEEvent*>expr_;
|
svector<PEEvent*>expr_;
|
||||||
|
|
|
||||||
|
|
@ -1077,7 +1077,15 @@ void NetEvTrig::dump(ostream&o, unsigned ind) const
|
||||||
|
|
||||||
void NetEvWait::dump(ostream&o, unsigned ind) const
|
void NetEvWait::dump(ostream&o, unsigned ind) const
|
||||||
{
|
{
|
||||||
o << setw(ind) <<"" << "@(";
|
o << setw(ind) << "";
|
||||||
|
|
||||||
|
/* Check for a wait fork. */
|
||||||
|
if ((nevents() == 1) && (event(0) == 0)) {
|
||||||
|
o << "wait fork;";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
o << "@(";
|
||||||
|
|
||||||
if (nevents() > 0)
|
if (nevents() > 0)
|
||||||
o << event(0)->name();
|
o << event(0)->name();
|
||||||
|
|
@ -1101,6 +1109,12 @@ ostream& operator << (ostream&out, const NetEvWait&obj)
|
||||||
|
|
||||||
void NetEvWait::dump_inline(ostream&o) const
|
void NetEvWait::dump_inline(ostream&o) const
|
||||||
{
|
{
|
||||||
|
/* Check for a wait fork. */
|
||||||
|
if ((nevents() == 1) && (event(0) == 0)) {
|
||||||
|
o << "wait fork;";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
o << "@(";
|
o << "@(";
|
||||||
|
|
||||||
if (nevents() > 0)
|
if (nevents() > 0)
|
||||||
|
|
|
||||||
48
elaborate.cc
48
elaborate.cc
|
|
@ -4232,9 +4232,57 @@ NetProc* PEventStatement::elaborate_wait(Design*des, NetScope*scope,
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a special case of the event statement, the wait fork
|
||||||
|
* statement. This is elaborated into a simplified statement.
|
||||||
|
*
|
||||||
|
* wait fork;
|
||||||
|
*
|
||||||
|
* becomes
|
||||||
|
*
|
||||||
|
* @(0) <noop>;
|
||||||
|
*/
|
||||||
|
NetProc* PEventStatement::elaborate_wait_fork(Design*des, NetScope*scope) const
|
||||||
|
{
|
||||||
|
assert(scope);
|
||||||
|
assert(expr_.count() == 1);
|
||||||
|
assert(expr_[0] == 0);
|
||||||
|
assert(! statement_);
|
||||||
|
|
||||||
|
if (scope->in_func()) {
|
||||||
|
cerr << get_fileline() << ": error: functions cannot have "
|
||||||
|
"wait fork statements." << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scope->in_final()) {
|
||||||
|
cerr << get_fileline() << ": error: final procedures cannot "
|
||||||
|
"have wait fork statements." << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gn_system_verilog()) {
|
||||||
|
NetEvWait*wait = new NetEvWait(0 /* noop */);
|
||||||
|
wait->add_event(0);
|
||||||
|
wait->set_line(*this);
|
||||||
|
return wait;
|
||||||
|
} else {
|
||||||
|
cerr << get_fileline()
|
||||||
|
<< ": error: 'wait fork' requires SystemVerilog." << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
NetProc* PEventStatement::elaborate(Design*des, NetScope*scope) const
|
NetProc* PEventStatement::elaborate(Design*des, NetScope*scope) const
|
||||||
{
|
{
|
||||||
|
/* Check to see if this is a wait fork statement. */
|
||||||
|
if ((expr_.count() == 1) && (expr_[0] == 0))
|
||||||
|
return elaborate_wait_fork(des, scope);
|
||||||
|
|
||||||
NetProc*enet = 0;
|
NetProc*enet = 0;
|
||||||
if (statement_) {
|
if (statement_) {
|
||||||
enet = statement_->elaborate(des, scope);
|
enet = statement_->elaborate(des, scope);
|
||||||
|
|
|
||||||
13
net_event.cc
13
net_event.cc
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2000-2010 Stephen Williams (steve@icarus.com)
|
* Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -372,11 +372,20 @@ NetEvWait::~NetEvWait()
|
||||||
|
|
||||||
void NetEvWait::add_event(NetEvent*tgt)
|
void NetEvWait::add_event(NetEvent*tgt)
|
||||||
{
|
{
|
||||||
assert(tgt);
|
/* A wait fork is an empty event. */
|
||||||
|
if (! tgt) {
|
||||||
|
assert(nevents_ == 0);
|
||||||
|
nevents_ = 1;
|
||||||
|
events_ = new NetEvent*[1];
|
||||||
|
events_[0] = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (nevents_ == 0) {
|
if (nevents_ == 0) {
|
||||||
events_ = new NetEvent*[1];
|
events_ = new NetEvent*[1];
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
assert(events_[0]);
|
||||||
NetEvent**tmp = new NetEvent*[nevents_+1];
|
NetEvent**tmp = new NetEvent*[nevents_+1];
|
||||||
for (unsigned idx = 0 ; idx < nevents_ ; idx += 1) {
|
for (unsigned idx = 0 ; idx < nevents_ ; idx += 1) {
|
||||||
tmp[idx] = events_[idx];
|
tmp[idx] = events_[idx];
|
||||||
|
|
|
||||||
5
parse.y
5
parse.y
|
|
@ -5784,6 +5784,11 @@ statement_item /* This is roughly statement_item in the LRM */
|
||||||
tmp->set_statement($5);
|
tmp->set_statement($5);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
|
| K_wait K_fork ';'
|
||||||
|
{ PEventStatement*tmp = new PEventStatement(0);
|
||||||
|
FILE_NAME(tmp,@1);
|
||||||
|
$$ = tmp;
|
||||||
|
}
|
||||||
| SYSTEM_IDENTIFIER '(' expression_list_with_nuls ')' ';'
|
| SYSTEM_IDENTIFIER '(' expression_list_with_nuls ')' ';'
|
||||||
{ PCallTask*tmp = new PCallTask(lex_strings.make($1), *$3);
|
{ PCallTask*tmp = new PCallTask(lex_strings.make($1), *$3);
|
||||||
FILE_NAME(tmp,@1);
|
FILE_NAME(tmp,@1);
|
||||||
|
|
|
||||||
|
|
@ -874,6 +874,9 @@ void PEventStatement::dump(ostream&out, unsigned ind) const
|
||||||
if (expr_.count() == 0) {
|
if (expr_.count() == 0) {
|
||||||
out << setw(ind) << "" << "@* ";
|
out << setw(ind) << "" << "@* ";
|
||||||
|
|
||||||
|
} else if ((expr_.count() == 1) && (expr_[0] == 0)) {
|
||||||
|
out << setw(ind) << "" << "wait fork ";
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
out << setw(ind) << "" << "@(" << *(expr_[0]);
|
out << setw(ind) << "" << "@(" << *(expr_[0]);
|
||||||
if (expr_.count() > 1)
|
if (expr_.count() > 1)
|
||||||
|
|
|
||||||
|
|
@ -805,8 +805,17 @@ bool dll_target::proc_wait(const NetEvWait*net)
|
||||||
stmt_cur_->u_.wait_.stmt_ = (struct ivl_statement_s*)
|
stmt_cur_->u_.wait_.stmt_ = (struct ivl_statement_s*)
|
||||||
calloc(1, sizeof(struct ivl_statement_s));
|
calloc(1, sizeof(struct ivl_statement_s));
|
||||||
|
|
||||||
// This event processing code is also in the NB assign above.
|
|
||||||
stmt_cur_->u_.wait_.nevent = net->nevents();
|
stmt_cur_->u_.wait_.nevent = net->nevents();
|
||||||
|
|
||||||
|
/* This is a wait fork statement. */
|
||||||
|
if ((net->nevents() == 1) && (net->event(0) == 0)) {
|
||||||
|
stmt_cur_->u_.wait_.event = 0;
|
||||||
|
stmt_cur_->type_ = IVL_ST_WAIT;
|
||||||
|
stmt_cur_->u_.wait_.stmt_->type_ = IVL_ST_NOOP;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This event processing code is also in the NB assign above.
|
||||||
if (net->nevents() > 1) {
|
if (net->nevents() > 1) {
|
||||||
stmt_cur_->u_.wait_.events = (ivl_event_t*)
|
stmt_cur_->u_.wait_.events = (ivl_event_t*)
|
||||||
calloc(net->nevents(), sizeof(ivl_event_t*));
|
calloc(net->nevents(), sizeof(ivl_event_t*));
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,16 @@ void show_stmt_wait(ivl_statement_t net, unsigned ind)
|
||||||
{
|
{
|
||||||
unsigned idx;
|
unsigned idx;
|
||||||
const char*comma = "";
|
const char*comma = "";
|
||||||
fprintf(out, "%*s@(", ind, "");
|
fprintf(out, "%*s", ind, "");
|
||||||
|
|
||||||
|
/* Emit a SystemVerilog wait fork. */
|
||||||
|
if ((ivl_stmt_nevent(net) == 1) && (ivl_stmt_events(net, 0) == 0)) {
|
||||||
|
assert(ivl_statement_type(ivl_stmt_sub_stmt(net)) == IVL_ST_NOOP);
|
||||||
|
fprintf(out, "wait fork;\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(out, "@(");
|
||||||
|
|
||||||
for (idx = 0 ; idx < ivl_stmt_nevent(net) ; idx += 1) {
|
for (idx = 0 ; idx < ivl_stmt_nevent(net) ; idx += 1) {
|
||||||
ivl_event_t evnt = ivl_stmt_events(net, idx);
|
ivl_event_t evnt = ivl_stmt_events(net, idx);
|
||||||
|
|
|
||||||
|
|
@ -1408,6 +1408,23 @@ static void emit_stmt_utask(ivl_scope_t scope, ivl_statement_t stmt)
|
||||||
fprintf(vlog_out, "\n");
|
fprintf(vlog_out, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Look to see if this is a SystemVerilog wait fork statement. */
|
||||||
|
static unsigned is_wait_fork(ivl_scope_t scope, ivl_statement_t stmt)
|
||||||
|
{
|
||||||
|
if (ivl_stmt_nevent(stmt) != 1) return 0;
|
||||||
|
if (ivl_stmt_events(stmt, 0) != 0) return 0;
|
||||||
|
assert(ivl_statement_type(ivl_stmt_sub_stmt(stmt)) == IVL_ST_NOOP);
|
||||||
|
|
||||||
|
fprintf(vlog_out, "%*cwait fork;", get_indent(), ' ');
|
||||||
|
emit_stmt_file_line(stmt);
|
||||||
|
fprintf(vlog_out, "\n");
|
||||||
|
fprintf(stderr, "%s:%u: vlog95 sorry: wait fork is not currently "
|
||||||
|
"translated.\n",
|
||||||
|
ivl_stmt_file(stmt), ivl_stmt_lineno(stmt));
|
||||||
|
vlog_errors += 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void emit_stmt_wait(ivl_scope_t scope, ivl_statement_t stmt)
|
static void emit_stmt_wait(ivl_scope_t scope, ivl_statement_t stmt)
|
||||||
{
|
{
|
||||||
fprintf(vlog_out, "%*c@(", get_indent(), ' ');
|
fprintf(vlog_out, "%*c@(", get_indent(), ' ');
|
||||||
|
|
@ -1540,6 +1557,7 @@ void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt)
|
||||||
emit_stmt_utask(scope, stmt);
|
emit_stmt_utask(scope, stmt);
|
||||||
break;
|
break;
|
||||||
case IVL_ST_WAIT:
|
case IVL_ST_WAIT:
|
||||||
|
if (is_wait_fork(scope, stmt)) break;
|
||||||
emit_stmt_wait(scope, stmt);
|
emit_stmt_wait(scope, stmt);
|
||||||
break;
|
break;
|
||||||
case IVL_ST_WHILE:
|
case IVL_ST_WHILE:
|
||||||
|
|
|
||||||
|
|
@ -1724,6 +1724,19 @@ static int show_stmt_utask(ivl_statement_t net)
|
||||||
|
|
||||||
static int show_stmt_wait(ivl_statement_t net, ivl_scope_t sscope)
|
static int show_stmt_wait(ivl_statement_t net, ivl_scope_t sscope)
|
||||||
{
|
{
|
||||||
|
/* Look to see if this is a SystemVerilog wait fork. */
|
||||||
|
if ((ivl_stmt_nevent(net) == 1) && (ivl_stmt_events(net, 0) == 0)) {
|
||||||
|
assert(ivl_statement_type(ivl_stmt_sub_stmt(net)) == IVL_ST_NOOP);
|
||||||
|
show_stmt_file_line(net, "Wait fork statement.");
|
||||||
|
fprintf(vvp_out, " %%wait_fork;\n");
|
||||||
|
|
||||||
|
fprintf(stderr, "%s:%u: vvp.tgt sorry: wait fork is not currently "
|
||||||
|
"supported.\n",
|
||||||
|
ivl_stmt_file(net), ivl_stmt_lineno(net));
|
||||||
|
vvp_errors += 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
show_stmt_file_line(net, "Event wait (@) statement.");
|
show_stmt_file_line(net, "Event wait (@) statement.");
|
||||||
|
|
||||||
if (ivl_stmt_nevent(net) == 1) {
|
if (ivl_stmt_nevent(net) == 1) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue