diff --git a/Statement.h b/Statement.h index 938eb55d6..52a3ecf32 100644 --- a/Statement.h +++ b/Statement.h @@ -391,6 +391,7 @@ class PEventStatement : public Statement { NetProc* elaborate_st(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: svectorexpr_; diff --git a/design_dump.cc b/design_dump.cc index cdc364826..3086f1b4b 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1077,7 +1077,15 @@ void NetEvTrig::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) o << event(0)->name(); @@ -1101,6 +1109,12 @@ ostream& operator << (ostream&out, const NetEvWait&obj) void NetEvWait::dump_inline(ostream&o) const { + /* Check for a wait fork. */ + if ((nevents() == 1) && (event(0) == 0)) { + o << "wait fork;"; + return; + } + o << "@("; if (nevents() > 0) diff --git a/elaborate.cc b/elaborate.cc index ac1924090..08b8f5066 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -4232,9 +4232,57 @@ NetProc* PEventStatement::elaborate_wait(Design*des, NetScope*scope, 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) ; + */ +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 { + /* 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; if (statement_) { enet = statement_->elaborate(des, scope); diff --git a/net_event.cc b/net_event.cc index e9c7de8ae..5ad61063a 100644 --- a/net_event.cc +++ b/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 * 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) { - 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) { events_ = new NetEvent*[1]; } else { + assert(events_[0]); NetEvent**tmp = new NetEvent*[nevents_+1]; for (unsigned idx = 0 ; idx < nevents_ ; idx += 1) { tmp[idx] = events_[idx]; diff --git a/parse.y b/parse.y index e26656d24..393aa6d10 100644 --- a/parse.y +++ b/parse.y @@ -5784,6 +5784,11 @@ statement_item /* This is roughly statement_item in the LRM */ tmp->set_statement($5); $$ = tmp; } + | K_wait K_fork ';' + { PEventStatement*tmp = new PEventStatement(0); + FILE_NAME(tmp,@1); + $$ = tmp; + } | SYSTEM_IDENTIFIER '(' expression_list_with_nuls ')' ';' { PCallTask*tmp = new PCallTask(lex_strings.make($1), *$3); FILE_NAME(tmp,@1); diff --git a/pform_dump.cc b/pform_dump.cc index 46f920e99..a744b3c96 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -874,6 +874,9 @@ void PEventStatement::dump(ostream&out, unsigned ind) const if (expr_.count() == 0) { out << setw(ind) << "" << "@* "; + } else if ((expr_.count() == 1) && (expr_[0] == 0)) { + out << setw(ind) << "" << "wait fork "; + } else { out << setw(ind) << "" << "@(" << *(expr_[0]); if (expr_.count() > 1) diff --git a/t-dll-proc.cc b/t-dll-proc.cc index 449cb4326..1bb369efd 100644 --- a/t-dll-proc.cc +++ b/t-dll-proc.cc @@ -805,8 +805,17 @@ bool dll_target::proc_wait(const NetEvWait*net) stmt_cur_->u_.wait_.stmt_ = (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(); + + /* 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) { stmt_cur_->u_.wait_.events = (ivl_event_t*) calloc(net->nevents(), sizeof(ivl_event_t*)); diff --git a/tgt-stub/statement.c b/tgt-stub/statement.c index 2e027b559..7e5204aa9 100644 --- a/tgt-stub/statement.c +++ b/tgt-stub/statement.c @@ -231,7 +231,16 @@ void show_stmt_wait(ivl_statement_t net, unsigned ind) { unsigned idx; 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) { ivl_event_t evnt = ivl_stmt_events(net, idx); diff --git a/tgt-vlog95/stmt.c b/tgt-vlog95/stmt.c index 6a30637ee..0cf39039d 100644 --- a/tgt-vlog95/stmt.c +++ b/tgt-vlog95/stmt.c @@ -1408,6 +1408,23 @@ static void emit_stmt_utask(ivl_scope_t scope, ivl_statement_t stmt) 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) { 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); break; case IVL_ST_WAIT: + if (is_wait_fork(scope, stmt)) break; emit_stmt_wait(scope, stmt); break; case IVL_ST_WHILE: diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 740fc4080..44731fc61 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -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) { + /* 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."); if (ivl_stmt_nevent(net) == 1) {