diff --git a/design_dump.cc b/design_dump.cc index cc7f0f293..5f1dcd91b 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -718,6 +718,11 @@ void NetProcTop::dump(ostream&o, unsigned ind) const statement_->dump(o, ind+2); } +void NetAlloc::dump(ostream&o, unsigned ind) const +{ + o << setw(ind) << "// allocate storage : " << scope_path(scope_) << endl; +} + void NetAssign_::dump_lval(ostream&o) const { if (sig_) { @@ -950,6 +955,11 @@ void NetForever::dump(ostream&o, unsigned ind) const statement_->dump(o, ind+2); } +void NetFree::dump(ostream&o, unsigned ind) const +{ + o << setw(ind) << "// free storage : " << scope_path(scope_) << endl; +} + void NetFuncDef::dump(ostream&o, unsigned ind) const { o << setw(ind) << "" << "function definition for " << scope_path(scope_) << endl; diff --git a/elaborate.cc b/elaborate.cc index bd8aa89f3..add19d661 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -2408,6 +2408,13 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const return block; } + /* If this is an automatic task, generate a statement to + allocate the local storage. */ + if (task->is_auto()) { + NetAlloc*ap = new NetAlloc(task); + block->append(ap); + } + /* Generate assignment statement statements for the input and INOUT ports of the task. These are managed by writing assignments with the task port the l-value and the passed @@ -2487,6 +2494,13 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const block->append(ass); } + /* If this is an automatic task, generate a statement to free + the local storage. */ + if (task->is_auto()) { + NetFree*fp = new NetFree(task); + block->append(fp); + } + return block; } diff --git a/emit.cc b/emit.cc index 1370cb617..6d1be63a8 100644 --- a/emit.cc +++ b/emit.cc @@ -196,6 +196,12 @@ bool NetProc::emit_proc(struct target_t*tgt) const return false; } +bool NetAlloc::emit_proc(struct target_t*tgt) const +{ + tgt->proc_alloc(this); + return true; +} + bool NetAssign::emit_proc(struct target_t*tgt) const { return tgt->proc_assign(this); @@ -249,6 +255,12 @@ bool NetForever::emit_proc(struct target_t*tgt) const return true; } +bool NetFree::emit_proc(struct target_t*tgt) const +{ + tgt->proc_free(this); + return true; +} + bool NetPDelay::emit_proc(struct target_t*tgt) const { return tgt->proc_delay(this); diff --git a/ivl_target.h b/ivl_target.h index 159ff7dac..021d57249 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -343,6 +343,7 @@ typedef enum ivl_signal_type_e { typedef enum ivl_statement_type_e { IVL_ST_NONE = 0, IVL_ST_NOOP = 1, + IVL_ST_ALLOC = 25, IVL_ST_ASSIGN = 2, IVL_ST_ASSIGN_NB = 3, IVL_ST_BLOCK = 4, @@ -359,6 +360,7 @@ typedef enum ivl_statement_type_e { IVL_ST_FORCE = 14, IVL_ST_FOREVER = 15, IVL_ST_FORK = 16, + IVL_ST_FREE = 26, IVL_ST_RELEASE = 17, IVL_ST_REPEAT = 18, IVL_ST_STASK = 19, diff --git a/netlist.cc b/netlist.cc index b4ce2697c..60d8ccd4c 100644 --- a/netlist.cc +++ b/netlist.cc @@ -1973,6 +1973,44 @@ const NetScope* NetUTask::task() const return task_; } +NetAlloc::NetAlloc(NetScope*scope) +: scope_(scope) +{ +} + +NetAlloc::~NetAlloc() +{ +} +#if 0 +const string NetAlloc::name() const +{ + return scope_->name(); +} +#endif +const NetScope* NetAlloc::scope() const +{ + return scope_; +} + +NetFree::NetFree(NetScope*scope) +: scope_(scope) +{ +} + +NetFree::~NetFree() +{ +} +#if 0 +const string NetFree::name() const +{ + return scope_->name(); +} +#endif +const NetScope* NetFree::scope() const +{ + return scope_; +} + NetExpr::NetExpr(unsigned w) : width_(w), signed_flag_(false) { diff --git a/netlist.h b/netlist.h index fc2d120f7..f0d2407c9 100644 --- a/netlist.h +++ b/netlist.h @@ -2086,6 +2086,23 @@ class NetProc : public virtual LineInfo { NetProc& operator= (const NetProc&); }; +class NetAlloc : public NetProc { + + public: + NetAlloc(NetScope*); + ~NetAlloc(); + + const string name() const; + + const NetScope* scope() const; + + virtual bool emit_proc(struct target_t*) const; + virtual void dump(ostream&, unsigned ind) const; + + private: + NetScope*scope_; +}; + /* * Procedural assignment is broken into a suite of classes. These * classes represent the various aspects of the assignment statement @@ -2705,6 +2722,23 @@ class NetForever : public NetProc { NetProc*statement_; }; +class NetFree : public NetProc { + + public: + NetFree(NetScope*); + ~NetFree(); + + const string name() const; + + const NetScope* scope() const; + + virtual bool emit_proc(struct target_t*) const; + virtual void dump(ostream&, unsigned ind) const; + + private: + NetScope*scope_; +}; + /* * A function definition is elaborated just like a task, though by now * it is certain that the first parameter (a phantom parameter) is the diff --git a/parse.y b/parse.y index 75bcf60dc..bbd049151 100644 --- a/parse.y +++ b/parse.y @@ -459,10 +459,10 @@ block_item_decl with real value. Note that real and realtime are interchangeable in this context. */ - | attribute_list_opt K_real real_variable_list ';' - { delete $3; } - | attribute_list_opt K_realtime real_variable_list ';' - { delete $3; } + | attribute_list_opt K_real real_variable_list ';' + { delete $3; } + | attribute_list_opt K_realtime real_variable_list ';' + { delete $3; } | K_event list_of_identifiers ';' { pform_make_events($2, @1.text, @1.first_line); diff --git a/t-dll-api.cc b/t-dll-api.cc index c68a61f32..ebfee98e5 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -1913,9 +1913,15 @@ extern "C" ivl_statement_t ivl_stmt_block_stmt(ivl_statement_t net, extern "C" ivl_scope_t ivl_stmt_call(ivl_statement_t net) { switch (net->type_) { + case IVL_ST_ALLOC: + return net->u_.alloc_.scope; + case IVL_ST_DISABLE: return net->u_.disable_.scope; + case IVL_ST_FREE: + return net->u_.free_.scope; + case IVL_ST_UTASK: return net->u_.utask_.def; default: diff --git a/t-dll-proc.cc b/t-dll-proc.cc index badf7cd78..b3b96973f 100644 --- a/t-dll-proc.cc +++ b/t-dll-proc.cc @@ -188,6 +188,16 @@ void dll_target::make_assign_lvals_(const NetAssignBase*net) } } +void dll_target::proc_alloc(const NetAlloc*net) +{ + assert(stmt_cur_); + assert(stmt_cur_->type_ == IVL_ST_NONE); + FILE_NAME(stmt_cur_, net); + + stmt_cur_->type_ = IVL_ST_ALLOC; + stmt_cur_->u_.alloc_.scope = lookup_scope_(net->scope()); +} + /* */ bool dll_target::proc_assign(const NetAssign*net) @@ -629,6 +639,16 @@ void dll_target::proc_forever(const NetForever*net) stmt_cur_ = save_cur_; } +void dll_target::proc_free(const NetFree*net) +{ + assert(stmt_cur_); + assert(stmt_cur_->type_ == IVL_ST_NONE); + FILE_NAME(stmt_cur_, net); + + stmt_cur_->type_ = IVL_ST_FREE; + stmt_cur_->u_.free_.scope = lookup_scope_(net->scope()); +} + bool dll_target::proc_release(const NetRelease*net) { assert(stmt_cur_); diff --git a/t-dll.h b/t-dll.h index 87047b9d4..7989ab8f9 100644 --- a/t-dll.h +++ b/t-dll.h @@ -115,6 +115,7 @@ struct dll_target : public target_t, public expr_scan_t { /* These methods and members are used for forming the statements of a thread. */ struct ivl_statement_s*stmt_cur_; + void proc_alloc(const NetAlloc*); bool proc_assign(const NetAssign*); void proc_assign_nb(const NetAssignNB*); bool proc_block(const NetBlock*); @@ -126,6 +127,7 @@ struct dll_target : public target_t, public expr_scan_t { bool proc_disable(const NetDisable*); bool proc_force(const NetForce*); void proc_forever(const NetForever*); + void proc_free(const NetFree*); bool proc_release(const NetRelease*); void proc_repeat(const NetRepeat*); void proc_stask(const NetSTask*); @@ -665,6 +667,10 @@ struct ivl_statement_s { unsigned lineno; union { + struct { /* IVL_ST_ALLOC */ + ivl_scope_t scope; + } alloc_; + struct { /* IVL_ST_ASSIGN IVL_ST_ASSIGN_NB IVL_ST_CASSIGN, IVL_ST_DEASSIGN */ unsigned lvals_; @@ -718,6 +724,10 @@ struct ivl_statement_s { ivl_statement_t stmt_; } forever_; + struct { /* IVL_ST_FREE */ + ivl_scope_t scope; + } free_; + struct { /* IVL_ST_STASK */ const char*name_; unsigned nparm_; diff --git a/target.cc b/target.cc index fef82cedb..00bd9d0cb 100644 --- a/target.cc +++ b/target.cc @@ -243,6 +243,12 @@ bool target_t::process(const NetProcTop*top) return top->statement()->emit_proc(this); } +void target_t::proc_alloc(const NetAlloc*) +{ + cerr << "target (" << typeid(*this).name() << "): " + "Unhandled proc_alloc." << endl; +} + bool target_t::proc_assign(const NetAssign*) { cerr << "target (" << typeid(*this).name() << "): " @@ -322,6 +328,12 @@ void target_t::proc_forever(const NetForever*) "Unhandled proc_forever." << endl; } +void target_t::proc_free(const NetFree*) +{ + cerr << "target (" << typeid(*this).name() << "): " + "Unhandled proc_free." << endl; +} + bool target_t::proc_release(const NetRelease*dev) { cerr << dev->get_fileline() << ": internal error: " diff --git a/target.h b/target.h index a266d6d15..2be4acf20 100644 --- a/target.h +++ b/target.h @@ -105,6 +105,7 @@ struct target_t { virtual bool process(const NetProcTop*); /* Various kinds of process nodes are dispatched through these. */ + virtual void proc_alloc(const NetAlloc*); virtual bool proc_assign(const NetAssign*); virtual void proc_assign_nb(const NetAssignNB*); virtual bool proc_block(const NetBlock*); @@ -116,6 +117,7 @@ struct target_t { virtual bool proc_disable(const NetDisable*); virtual bool proc_force(const NetForce*); virtual void proc_forever(const NetForever*); + virtual void proc_free(const NetFree*); virtual bool proc_release(const NetRelease*); virtual void proc_repeat(const NetRepeat*); virtual bool proc_trigger(const NetEvTrig*); diff --git a/tgt-stub/statement.c b/tgt-stub/statement.c index bf560cf5f..b7807bbcb 100644 --- a/tgt-stub/statement.c +++ b/tgt-stub/statement.c @@ -183,6 +183,10 @@ void show_statement(ivl_statement_t net, unsigned ind) switch (code) { + case IVL_ST_ALLOC: + fprintf(out, "%*sallocate automatic storage ...\n", ind, ""); + break; + case IVL_ST_ASSIGN: fprintf(out, "%*sASSIGN \n", ind, "", ivl_stmt_lwidth(net)); @@ -316,6 +320,10 @@ void show_statement(ivl_statement_t net, unsigned ind) break; } + case IVL_ST_FREE: + fprintf(out, "%*sfree automatic storage ...\n", ind, ""); + break; + case IVL_ST_NOOP: fprintf(out, "%*s/* noop */;\n", ind, ""); break; @@ -356,4 +364,3 @@ void show_statement(ivl_statement_t net, unsigned ind) fprintf(out, "%*sunknown statement type (%u)\n", ind, "", code); } } - diff --git a/tgt-vvp/draw_ufunc.c b/tgt-vvp/draw_ufunc.c index 6ea3b3637..5a1cfcf44 100644 --- a/tgt-vvp/draw_ufunc.c +++ b/tgt-vvp/draw_ufunc.c @@ -88,6 +88,11 @@ struct vector_info draw_ufunc_expr(ivl_expr_t exp, unsigned wid) ivl_signal_t retval = ivl_scope_port(def, 0); struct vector_info res; + /* If this is an automatic function, allocate the local storage. */ + if (ivl_scope_is_auto(def)) { + fprintf(vvp_out, " %%alloc S_%p;\n", def); + } + /* evaluate the expressions and send the results to the function ports. */ @@ -134,6 +139,11 @@ struct vector_info draw_ufunc_expr(ivl_expr_t exp, unsigned wid) if (load_wid < wid) pad_expr_in_place(exp, res, swid); + /* If this is an automatic function, free the local storage. */ + if (ivl_scope_is_auto(def)) { + fprintf(vvp_out, " %%free S_%p;\n", def); + } + return res; } @@ -144,6 +154,11 @@ int draw_ufunc_real(ivl_expr_t exp) int res = 0; int idx; + /* If this is an automatic function, allocate the local storage. */ + if (ivl_scope_is_auto(def)) { + fprintf(vvp_out, " %%alloc S_%p;\n", def); + } + assert(ivl_expr_parms(exp) == (ivl_scope_ports(def)-1)); for (idx = 0 ; idx < ivl_expr_parms(exp) ; idx += 1) { ivl_signal_t port = ivl_scope_port(def, idx+1); @@ -163,6 +178,10 @@ int draw_ufunc_real(ivl_expr_t exp) res = allocate_word(); fprintf(vvp_out, " %%load/wr %d, v%p_0;\n", res, retval); + /* If this is an automatic function, free the local storage. */ + if (ivl_scope_is_auto(def)) { + fprintf(vvp_out, " %%free S_%p;\n", def); + } + return res; } - diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index e6233a363..e23143aa4 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -428,6 +428,14 @@ static void set_vec_to_lval(ivl_statement_t net, struct vector_info res) } } +static int show_stmt_alloc(ivl_statement_t net) +{ + ivl_scope_t scope = ivl_stmt_call(net); + + fprintf(vvp_out, " %%alloc S_%p;\n", scope); + return 0; +} + static int show_stmt_assign_vector(ivl_statement_t net) { ivl_expr_t rval = ivl_stmt_rval(net); @@ -1398,6 +1406,14 @@ static int show_stmt_fork(ivl_statement_t net, ivl_scope_t sscope) return rc; } +static int show_stmt_free(ivl_statement_t net) +{ + ivl_scope_t scope = ivl_stmt_call(net); + + fprintf(vvp_out, " %%free S_%p;\n", scope); + return 0; +} + /* * noop statements are implemented by doing nothing. */ @@ -1645,6 +1661,10 @@ static int show_statement(ivl_statement_t net, ivl_scope_t sscope) switch (code) { + case IVL_ST_ALLOC: + rc += show_stmt_alloc(net); + break; + case IVL_ST_ASSIGN: rc += show_stmt_assign(net); break; @@ -1706,6 +1726,10 @@ static int show_statement(ivl_statement_t net, ivl_scope_t sscope) rc += show_stmt_fork(net, sscope); break; + case IVL_ST_FREE: + rc += show_stmt_free(net); + break; + case IVL_ST_NOOP: rc += show_stmt_noop(net); break; diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 32780a41d..75f36fc9c 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -1581,7 +1581,7 @@ static void draw_lpm_ufunc(ivl_lpm_t net) fprintf(vvp_out, ")"); - /* Finally, print the reference to the signal from which the + /* Now print the reference to the signal from which the result is collected. */ { ivl_signal_t psig = ivl_scope_port(def, 0); assert(ivl_lpm_width(net) == ivl_signal_width(psig)); @@ -1590,7 +1590,8 @@ static void draw_lpm_ufunc(ivl_lpm_t net) fprintf(vvp_out, " v%p_0", psig); } - fprintf(vvp_out, ";\n"); + /* Finally, print the scope identifier. */ + fprintf(vvp_out, " S_%p;\n", def); } /* @@ -1774,13 +1775,9 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) { unsigned idx; const char *type; - /* For now we do not support automatic tasks or functions. */ - if (ivl_scope_is_auto(net)) { - fprintf(stderr, "%s:%u: vvp-tgt sorry: automatic tasks/functions " - "are not supported!\n", - ivl_scope_def_file(net), ivl_scope_def_lineno(net)); - exit(1); - } + + const char*prefix = ivl_scope_is_auto(net) ? "auto" : ""; + switch (ivl_scope_type(net)) { case IVL_SCT_MODULE: type = "module"; break; case IVL_SCT_FUNCTION: type = "function"; break; @@ -1791,8 +1788,8 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) default: type = "?"; assert(0); } - fprintf(vvp_out, "S_%p .scope %s, \"%s\" \"%s\" %d %d", - net, type, vvp_mangle_name(ivl_scope_basename(net)), + fprintf(vvp_out, "S_%p .scope %s%s, \"%s\" \"%s\" %d %d", + net, prefix, type, vvp_mangle_name(ivl_scope_basename(net)), ivl_scope_tname(net), ivl_file_table_index(ivl_scope_file(net)), ivl_scope_lineno(net)); diff --git a/vvp/README.txt b/vvp/README.txt index 188f58e36..4781f6814 100644 --- a/vvp/README.txt +++ b/vvp/README.txt @@ -96,8 +96,8 @@ The syntax of a scope statement is: