From 1b178d56b7057b3416e30e19e823b29c6b1bc455 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 23 May 2013 19:59:57 -0700 Subject: [PATCH] Add support for SystemVerilog return statements. --- Statement.cc | 12 ++++++++- Statement.h | 13 +++++++++ elaborate.cc | 63 ++++++++++++++++++++++++++++++++++++++++++++ parse.y | 10 ++++--- pform_dump.cc | 9 ++++++- tgt-stub/statement.c | 12 ++++++++- 6 files changed, 112 insertions(+), 7 deletions(-) diff --git a/Statement.cc b/Statement.cc index 79d63fb63..a5e2677bd 100644 --- a/Statement.cc +++ b/Statement.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2008,2010,2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2008,2010,2012-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 @@ -329,6 +329,16 @@ PRepeat::~PRepeat() delete statement_; } +PReturn::PReturn(PExpr*e) +: expr_(e) +{ +} + +PReturn::~PReturn() +{ + delete expr_; +} + PTrigger::PTrigger(const pform_name_t&e) : event_(e) { diff --git a/Statement.h b/Statement.h index 43f299443..3091490e6 100644 --- a/Statement.h +++ b/Statement.h @@ -462,6 +462,19 @@ class PRelease : public Statement { PExpr*lval_; }; +class PReturn : public Statement { + + public: + explicit PReturn(PExpr*e); + ~PReturn(); + + NetProc* elaborate(Design*des, NetScope*scope) const; + virtual void dump(std::ostream&out, unsigned ind) const; + + private: + PExpr*expr_; +}; + /* * The PTrigger statement sends a trigger to a named event. Take the * name here. diff --git a/elaborate.cc b/elaborate.cc index 29f1cca24..6af548058 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -4443,6 +4443,69 @@ NetProc* PRepeat::elaborate(Design*des, NetScope*scope) const return proc; } +NetProc* PReturn::elaborate(Design*des, NetScope*scope) const +{ + NetScope*target = scope; + for (;;) { + if (target == 0) { + cerr << get_fileline() << ": error: " + << "Return statement is not in a function." << endl; + des->errors += 1; + return 0; + } + + if (target->type() == NetScope::FUNC) + break; + + if (target->type() == NetScope::TASK) { + cerr << get_fileline() << ": error: " + << "Cannot \"return\" from tasks." << endl; + des->errors += 1; + return 0; + } + + if (target->type()==NetScope::BEGIN_END) { + target = target->parent(); + continue; + } + + cerr << get_fileline() << ": error: " + << "Cannot \"return\" from this scope: " << scope_path(target) << endl; + des->errors += 1; + return 0; + } + + // We don't yet support void functions, so require an + // expression for the return statement. + if (expr_ == 0) { + cerr << get_fileline() << ": error: " + << "Return from " << scope_path(target) + << " requires a return value expression." << endl; + des->errors += 1; + return 0; + } + + NetNet*res = target->find_signal(target->basename()); + ivl_variable_type_t lv_type = res->data_type(); + unsigned long wid = res->vector_width(); + NetAssign_*lv = new NetAssign_(res); + + NetExpr*val = elaborate_rval_expr(des, scope, lv_type, wid, expr_); + + NetBlock*proc = new NetBlock(NetBlock::SEQU, 0); + proc->set_line( *this ); + + NetAssign*assn = new NetAssign(lv, val); + assn->set_line( *this ); + proc->append(assn); + + NetDisable*disa = new NetDisable(target); + disa->set_line( *this ); + proc->append( disa ); + + return proc; +} + /* * A task definition is elaborated by elaborating the statement that * it contains, and connecting its ports to NetNet objects. The diff --git a/parse.y b/parse.y index 20e62f77e..6ace0aa1e 100644 --- a/parse.y +++ b/parse.y @@ -1229,12 +1229,14 @@ jump_statement /* IEEE1800-2005: A.6.5 */ $$ = 0; } | K_return ';' - { yyerror(@1, "sorry: return statements not supported."); - $$ = 0; + { PReturn*tmp = new PReturn(0); + FILE_NAME(tmp, @1); + $$ = tmp; } | K_return expression ';' - { yyerror(@1, "sorry: return statements not supported."); - $$ = 0; + { PReturn*tmp = new PReturn($2); + FILE_NAME(tmp, @1); + $$ = tmp; } ; diff --git a/pform_dump.cc b/pform_dump.cc index feb274697..dafa6fd12 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -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 @@ -928,6 +928,13 @@ void PRepeat::dump(ostream&out, unsigned ind) const statement_->dump(out, ind+3); } +void PReturn::dump(ostream&fd, unsigned ind) const +{ + fd << setw(ind) << "" << "return ("; + if (expr_) fd << *expr_; + fd << ")" << endl; +} + void PTask::dump(ostream&out, unsigned ind) const { out << setw(ind) << "" << "task "; diff --git a/tgt-stub/statement.c b/tgt-stub/statement.c index ea020b6f0..eed16f055 100644 --- a/tgt-stub/statement.c +++ b/tgt-stub/statement.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-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 @@ -153,6 +153,12 @@ static void show_stmt_delayx(ivl_statement_t net, unsigned ind) show_statement(ivl_stmt_sub_stmt(net), ind+2); } +static void show_stmt_disable(ivl_statement_t net, unsigned ind) +{ + ivl_scope_t scope = ivl_stmt_call(net); + fprintf(out, "%*sdisable %s\n", ind, "", ivl_scope_basename(scope)); +} + static void show_stmt_force(ivl_statement_t net, unsigned ind) { unsigned idx; @@ -378,6 +384,10 @@ void show_statement(ivl_statement_t net, unsigned ind) show_stmt_delayx(net, ind); break; + case IVL_ST_DISABLE: + show_stmt_disable(net, ind); + break; + case IVL_ST_FORCE: show_stmt_force(net, ind); break;