From acb4ca8e47206edd08f1ab09ab06b64ec95606c2 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 4 Dec 2015 17:16:27 +0100 Subject: [PATCH 01/25] vhdlpp: More descriptive error message for a missing function. --- vhdlpp/expression_emit.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 8874da8e6..67104e13c 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -583,7 +583,10 @@ int ExpFunc::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; - ivl_assert(*this, def_); + if(!def_) { + cerr << get_fileline() << ": error: unknown function: " << name_ << endl; + return 1; + } // If this function has an elaborated definition, and if // that definition is in a package, then include the From 597001ee2f214f15bbe361593eb0fcaddb68fd66 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 4 Dec 2015 17:42:54 +0100 Subject: [PATCH 02/25] vhdlpp: Variables have always reg_flag set. --- vhdlpp/vsignal.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vhdlpp/vsignal.cc b/vhdlpp/vsignal.cc index 38516dbaf..68cec4c4a 100644 --- a/vhdlpp/vsignal.cc +++ b/vhdlpp/vsignal.cc @@ -72,8 +72,7 @@ int Variable::emit(ostream&out, Entity*ent, ScopeBase*scope) VType::decl_t decl; type_elaborate_(decl); - if (peek_refcnt_sequ_() > 0 || !peek_type()->can_be_packed()) - decl.reg_flag = true; + decl.reg_flag = true; errors += decl.emit(out, peek_name()); Expression*init_expr = peek_init_expr(); From 442750ca2c1d2cee567b760fb0bc37f716787996 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 4 Dec 2015 17:44:35 +0100 Subject: [PATCH 03/25] vhdlpp: Refactored {Report,Assert}Stmt so they handle expressions instead of strings. --- vhdlpp/parse.y | 5 ++--- vhdlpp/sequential.cc | 12 +++++------- vhdlpp/sequential.h | 13 ++++++++----- vhdlpp/sequential_debug.cc | 16 ++++++++++++---- vhdlpp/sequential_elaborate.cc | 10 +++++++++- vhdlpp/sequential_emit.cc | 22 +++++++++++++--------- 6 files changed, 49 insertions(+), 29 deletions(-) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 0c6884253..557284ad4 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -452,7 +452,7 @@ assertion_statement : K_assert expression report_statement { ReportStmt*report = dynamic_cast($3); assert(report); - AssertStmt*tmp = new AssertStmt($2, report->message().c_str(), report->severity()); + AssertStmt*tmp = new AssertStmt($2, report->message(), report->severity()); delete report; FILE_NAME(tmp,@2); $$ = tmp; @@ -2185,10 +2185,9 @@ relation ; report_statement - : K_report STRING_LITERAL severity_opt ';' + : K_report expression severity_opt ';' { ReportStmt*tmp = new ReportStmt($2, $3); FILE_NAME(tmp,@2); - delete[]$2; $$ = tmp; } diff --git a/vhdlpp/sequential.cc b/vhdlpp/sequential.cc index 042850426..f3c1d1c4a 100644 --- a/vhdlpp/sequential.cc +++ b/vhdlpp/sequential.cc @@ -278,26 +278,24 @@ BasicLoopStatement::~BasicLoopStatement() { } -ReportStmt::ReportStmt(const char*msg, severity_t sev) +ReportStmt::ReportStmt(Expression*msg, severity_t sev) : msg_(msg), severity_(sev) { if(sev == ReportStmt::UNSPECIFIED) severity_ = ReportStmt::NOTE; } -AssertStmt::AssertStmt(Expression*condition, const char*msg, ReportStmt::severity_t sev) -: ReportStmt("", sev), cond_(condition) +AssertStmt::AssertStmt(Expression*condition, Expression*msg, ReportStmt::severity_t sev) +: ReportStmt(msg, sev), cond_(condition) { if(msg == NULL) - msg_ = default_msg_; - else - msg_ = std::string(msg); + msg_ = new ExpString(default_msg_); if(sev == ReportStmt::UNSPECIFIED) severity_ = ReportStmt::ERROR; } -const std::string AssertStmt::default_msg_ = std::string("Assertion violation."); +const char*AssertStmt::default_msg_ = "Assertion violation."; WaitForStmt::WaitForStmt(Expression*delay) : delay_(delay) diff --git a/vhdlpp/sequential.h b/vhdlpp/sequential.h index a952981c0..2ddd00fd4 100644 --- a/vhdlpp/sequential.h +++ b/vhdlpp/sequential.h @@ -280,24 +280,27 @@ class ReportStmt : public SequentialStmt { public: typedef enum { UNSPECIFIED, NOTE, WARNING, ERROR, FAILURE } severity_t; - ReportStmt(const char*message, severity_t severity = NOTE); + ReportStmt(Expression*message, severity_t severity); virtual ~ReportStmt() {} void dump(ostream&out, int indent) const; + int elaborate(Entity*ent, ScopeBase*scope); int emit(ostream&out, Entity*entity, ScopeBase*scope); void write_to_stream(std::ostream&fd); - inline const std::string& message() const { return msg_; } + inline Expression*message() const { return msg_; } inline severity_t severity() const { return severity_; } protected: - std::string msg_; + void dump_sev_msg(ostream&out, int indent) const; + + Expression*msg_; severity_t severity_; }; class AssertStmt : public ReportStmt { public: - AssertStmt(Expression*condition, const char*message, + AssertStmt(Expression*condition, Expression*message, ReportStmt::severity_t severity = ReportStmt::ERROR); void dump(ostream&out, int indent) const; @@ -309,7 +312,7 @@ class AssertStmt : public ReportStmt { Expression*cond_; // Message displayed when there is no report assigned. - static const std::string default_msg_; + static const char*default_msg_; }; class WaitForStmt : public SequentialStmt { diff --git a/vhdlpp/sequential_debug.cc b/vhdlpp/sequential_debug.cc index 149021440..7abb63d6f 100644 --- a/vhdlpp/sequential_debug.cc +++ b/vhdlpp/sequential_debug.cc @@ -169,16 +169,24 @@ void BasicLoopStatement::dump(ostream&out, int indent) const void ReportStmt::dump(ostream&out, int indent) const { out << setw(indent) << "" << "ReportStmt at file=" << get_fileline() << endl; - out << setw(indent+3) << "" << "severity: " << severity_ << endl; - out << setw(indent+3) << "" << "message: " << msg_ << endl; + dump_sev_msg(out, indent+3); +} + +void ReportStmt::dump_sev_msg(ostream&out, int indent) const +{ + out << setw(indent) << "" << "severity: " << severity_ << endl; + + if(msg_) { + out << setw(indent) << "" << "message: "; + msg_->dump(out, indent); + } } void AssertStmt::dump(ostream&out, int indent) const { out << setw(indent) << "" << "AssertStmt at file=" << get_fileline() << endl; out << setw(indent+3) << "" << "condition: "; - cond_->dump(out, indent+3); - ReportStmt::dump(out, indent+3); + dump_sev_msg(out, indent+3); } void WaitForStmt::dump(ostream&out, int indent) const diff --git a/vhdlpp/sequential_elaborate.cc b/vhdlpp/sequential_elaborate.cc index 4b033c6e5..98b8766c0 100644 --- a/vhdlpp/sequential_elaborate.cc +++ b/vhdlpp/sequential_elaborate.cc @@ -217,9 +217,17 @@ int BasicLoopStatement::elaborate(Entity*, ScopeBase*) return 0; } +int ReportStmt::elaborate(Entity*ent, ScopeBase*scope) +{ + return msg_->elaborate_expr(ent, scope, &primitive_STRING); +} + int AssertStmt::elaborate(Entity*ent, ScopeBase*scope) { - return cond_->elaborate_expr(ent, scope, cond_->probe_type(ent, scope)); + int errors = 0; + errors += ReportStmt::elaborate(ent, scope); + errors += cond_->elaborate_expr(ent, scope, cond_->probe_type(ent, scope)); + return errors; } int WaitForStmt::elaborate(Entity*ent, ScopeBase*scope) diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index 9e122b213..8c2ea1fa7 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -496,21 +496,23 @@ int ForLoopStatement::emit_runtime_(ostream&out, Entity*ent, ScopeBase*scope) return errors; } -int ReportStmt::emit(ostream&out, Entity*, ScopeBase*) +int ReportStmt::emit(ostream&out, Entity*ent, ScopeBase*scope) { - out << "$display(\""; + out << "$display(\"** "; switch(severity_) { - case NOTE: out << "** Note: "; break; - case WARNING: out << "** Warning: "; break; - case ERROR: out << "** Error: "; break; - case FAILURE: out << "** Failure: "; break; + case NOTE: out << "Note"; break; + case WARNING: out << "Warning"; break; + case ERROR: out << "Error"; break; + case FAILURE: out << "Failure"; break; case UNSPECIFIED: ivl_assert(*this, false); break; } - out << ExpString::escape_quot(msg_); - out << " (" << get_fileline() << ")\");"; + out << ": \","; + + msg_->emit(out, ent, scope); + out << ",\" (" << get_fileline() << ")\");"; if(severity_ == FAILURE) out << "$finish();"; @@ -522,7 +524,9 @@ int ReportStmt::emit(ostream&out, Entity*, ScopeBase*) void ReportStmt::write_to_stream(std::ostream&fd) { - fd << "report \"" << ExpString::escape_quot(msg_) << "\"" << std::endl; + fd << "report \""; + msg_->write_to_stream(fd); + fd << "\"" << std::endl; fd << "severity "; switch(severity_) From ef3d0e4e0db3de9cfe53f9ebc1b1e7f54d1fc465 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 4 Dec 2015 17:45:20 +0100 Subject: [PATCH 04/25] vhdlpp: ExpString::emit distinguishes between array and string types. --- vhdlpp/expression_emit.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 67104e13c..7e4abb504 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -912,10 +912,11 @@ bool ExpString::is_primary(void) const int ExpString::emit(ostream& out, Entity*ent, ScopeBase*scope) { + const VTypeArray*arr; const VType*type = peek_type(); assert(type != 0); - if (const VTypeArray*arr = dynamic_cast(type)) { + if (type != &primitive_STRING && (arr = dynamic_cast(type))) { return emit_as_array_(out, ent, scope, arr); } From 1c4b1c12e41ab40c4efd4b50ab3531056067f5d0 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 7 Dec 2015 15:02:30 +0100 Subject: [PATCH 05/25] vhdlpp: Fixes for 'wait for' statements emission. --- vhdlpp/sequential_emit.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index 8c2ea1fa7..c5309c039 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -567,7 +567,7 @@ int WaitForStmt::emit(ostream&out, Entity*ent, ScopeBase*scope) out << "#("; errors += delay_->emit(out, ent, scope); - out << ")"; + out << ");" << std::endl; return errors; } @@ -590,6 +590,7 @@ int WaitStmt::emit(ostream&out, Entity*ent, ScopeBase*scope) case UNTIL: if(!sens_list_.empty()) { out << "@("; + for(std::set::iterator it = sens_list_.begin(); it != sens_list_.end(); ++it) { if(it != sens_list_.begin()) @@ -598,7 +599,7 @@ int WaitStmt::emit(ostream&out, Entity*ent, ScopeBase*scope) (*it)->emit(out, ent, scope); } - out << ");"; + out << "); "; } out << "wait("; From 9886b8cb363cd65b86b6257c525fd307edad40a7 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 7 Dec 2015 16:14:22 +0100 Subject: [PATCH 06/25] vhdlpp: Distinguish character and an array of bits during emission. --- vhdlpp/expression_emit.cc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 7e4abb504..41436a933 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -453,17 +453,16 @@ int ExpCharacter::emit_primitive_bit_(ostream&out, Entity*, ScopeBase*, int ExpCharacter::emit(ostream&out, Entity*ent, ScopeBase*scope) { const VType*etype = peek_type(); + const VTypeArray*array; + + if (etype != &primitive_CHARACTER && (array = dynamic_cast(etype))) { + etype = array->element_type(); + } if (const VTypePrimitive*use_type = dynamic_cast(etype)) { return emit_primitive_bit_(out, ent, scope, use_type); } - if (const VTypeArray*array = dynamic_cast(etype)) { - if (const VTypePrimitive*use_type = dynamic_cast(array->element_type())) { - return emit_primitive_bit_(out, ent, scope, use_type); - } - } - out << "\"" << value_ << "\""; return 0; } From df6b24fd3a7d45e64e237967595ee40233248a05 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 9 Dec 2015 14:24:19 +0100 Subject: [PATCH 07/25] ivl & vvp: Enabled 'string' as the return type in VPI functions. --- driver/iverilog.man.in | 5 ++++ sv_vpi_user.h | 4 +++ sys_funcs.cc | 11 +++++++++ tgt-vvp/draw_vpi.c | 11 +++++++++ tgt-vvp/eval_string.c | 8 +++++- tgt-vvp/vvp_priv.h | 1 + vvp/README.txt | 1 + vvp/lexor.lex | 1 + vvp/opcodes.txt | 1 + vvp/parse.y | 6 ++++- vvp/vpi_tasks.cc | 55 ++++++++++++++++++++++++++++++++++++++++-- vvp/vthread.cc | 5 ++++ vvp/vthread.h | 1 + 13 files changed, 106 insertions(+), 4 deletions(-) diff --git a/driver/iverilog.man.in b/driver/iverilog.man.in index bf7d986be..edc967d11 100644 --- a/driver/iverilog.man.in +++ b/driver/iverilog.man.in @@ -384,6 +384,11 @@ The function returns an integer. The function returns a vector with the given width, and is signed or unsigned according to the flag. +.TP 8 +.B vpiSysFuncString +The function returns a string. This is an Icarus-specific extension, not +available in the VPI standard. + .SH "COMMAND FILES" The command file allows the user to place source file names and certain command line switches into a text file instead of on a long diff --git a/sv_vpi_user.h b/sv_vpi_user.h index 1282e0ee2..8e6d21aae 100644 --- a/sv_vpi_user.h +++ b/sv_vpi_user.h @@ -72,6 +72,10 @@ EXTERN_C_START /********* Many-to-One ***********/ #define vpiMember 742 +/* Icarus-specific function type to use string as the return type */ +#define vpiStringFunc 10 +#define vpiSysFuncString vpiSysFuncString + EXTERN_C_END #endif /* SV_VPI_USER_H */ diff --git a/sys_funcs.cc b/sys_funcs.cc index 3e2b26a51..bb1ccd8bc 100644 --- a/sys_funcs.cc +++ b/sys_funcs.cc @@ -204,6 +204,17 @@ int load_sys_func_table(const char*path) continue; } + if (strcmp(stype,"vpiSysFuncString") == 0) { + cell = new struct sfunc_return_type_cell; + cell->name = lex_strings.add(name); + cell->type = IVL_VT_STRING; + cell->wid = 0; // string is a dynamic length type + cell->signed_flag = false; + cell->next = sfunc_stack; + sfunc_stack = cell; + continue; + } + fprintf(stderr, "%s:%s: Unknown type: %s\n", path, name, stype); } diff --git a/tgt-vvp/draw_vpi.c b/tgt-vvp/draw_vpi.c index 3587815eb..5239661a3 100644 --- a/tgt-vvp/draw_vpi.c +++ b/tgt-vvp/draw_vpi.c @@ -513,3 +513,14 @@ void draw_vpi_rfunc_call(ivl_expr_t fnet) draw_vpi_taskfunc_args(call_string, 0, fnet); } + +void draw_vpi_sfunc_call(ivl_expr_t fnet) +{ + char call_string[1024]; + + sprintf(call_string, " %%vpi_func/s %u %u \"%s\"", + ivl_file_table_index(ivl_expr_file(fnet)), + ivl_expr_lineno(fnet), ivl_expr_name(fnet)); + + draw_vpi_taskfunc_args(call_string, 0, fnet); +} diff --git a/tgt-vvp/eval_string.c b/tgt-vvp/eval_string.c index 92d702058..8cdb26338 100644 --- a/tgt-vvp/eval_string.c +++ b/tgt-vvp/eval_string.c @@ -163,6 +163,12 @@ static void string_ex_pop(ivl_expr_t expr) fprintf(vvp_out, " %%qpop/%s/str v%p_0;\n", fb, ivl_expr_signal(arg)); } +static void draw_sfunc_string(ivl_expr_t expr) +{ + assert(ivl_expr_value(expr) == IVL_VT_STRING); + draw_vpi_sfunc_call(expr); +} + void draw_eval_string(ivl_expr_t expr) { @@ -195,7 +201,7 @@ void draw_eval_string(ivl_expr_t expr) else if (strcmp(ivl_expr_name(expr), "$ivl_darray_method$pop_front")==0) string_ex_pop(expr); else - fallback_eval(expr); + draw_sfunc_string(expr); break; case IVL_EX_UFUNC: diff --git a/tgt-vvp/vvp_priv.h b/tgt-vvp/vvp_priv.h index 5255058cc..f4271620c 100644 --- a/tgt-vvp/vvp_priv.h +++ b/tgt-vvp/vvp_priv.h @@ -133,6 +133,7 @@ extern void draw_vpi_task_call(ivl_statement_t net); extern void draw_vpi_func_call(ivl_expr_t expr); extern void draw_vpi_rfunc_call(ivl_expr_t expr); +extern void draw_vpi_sfunc_call(ivl_expr_t expr); extern void draw_class_in_scope(ivl_type_t classtype); diff --git a/vvp/README.txt b/vvp/README.txt index f74cf2fa6..7f717bb91 100644 --- a/vvp/README.txt +++ b/vvp/README.txt @@ -841,6 +841,7 @@ instructions. The formats are: %vpi_call/i , ... ; %vpi_func , ... ; %vpi_func/r , ... ; + %vpi_func/s , ... ; The is an index into the string table. The indexed string is the source code file name where this call appears. The is diff --git a/vvp/lexor.lex b/vvp/lexor.lex index 2b2a81f0d..f442f16ec 100644 --- a/vvp/lexor.lex +++ b/vvp/lexor.lex @@ -234,6 +234,7 @@ static char* strdupnew(char const *str) "%vpi_call/i" { return K_vpi_call_i; } "%vpi_func" { return K_vpi_func; } "%vpi_func/r" { return K_vpi_func_r; } +"%vpi_func/s" { return K_vpi_func_s; } "%file_line" { return K_file_line; } /* Handle the specialized variable access functions. */ diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index d5adfa4a4..43eca604f 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -1213,6 +1213,7 @@ stack when the call returns. * %vpi_func [, ...] { } * %vpi_func/r [, ...] { } +* %vpi_func/s [, ...] { } This instruction is similar to %vpi_call, except that it is for calling system functions. The difference here is the return value from diff --git a/vvp/parse.y b/vvp/parse.y index d54dac6c3..22da1cf18 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -100,7 +100,7 @@ static struct __vpiModPath*modpath_dst = 0; %token K_VAR_QUEUE %token K_VAR_S K_VAR_STR K_VAR_I K_VAR_R K_VAR_2S K_VAR_2U %token K_vpi_call K_vpi_call_w K_vpi_call_i -%token K_vpi_func K_vpi_func_r +%token K_vpi_func K_vpi_func_r K_vpi_func_s %token K_ivl_version K_ivl_delay_selection %token K_vpi_module K_vpi_time_precision K_file_names K_file_line %token K_PORT_INPUT K_PORT_OUTPUT K_PORT_INOUT K_PORT_MIXED K_PORT_NODIR @@ -663,6 +663,10 @@ statement { compile_vpi_func_call($1, $5, -vpiRealVal, 0, $3, $4, $6.argc, $6.argv, $8, $9, $10); } + | label_opt K_vpi_func_s T_NUMBER T_NUMBER T_STRING + argument_opt '{' T_NUMBER T_NUMBER T_NUMBER '}' ';' + { compile_vpi_func_call($1, $5, -vpiStringVal, 0, $3, $4, + $6.argc, $6.argv, $8, $9, $10); } /* Scope statements come in two forms. There are the scope declaration and the scope recall. The declarations create the diff --git a/vvp/vpi_tasks.cc b/vvp/vpi_tasks.cc index 4f35903c7..94df6f573 100644 --- a/vvp/vpi_tasks.cc +++ b/vvp/vpi_tasks.cc @@ -211,6 +211,51 @@ vpiHandle sysfunc_real::vpi_put_value(p_vpi_value vp, int) return 0; } +struct sysfunc_string : public __vpiSysTaskCall { + inline sysfunc_string() { } + int get_type_code(void) const { return vpiSysFuncCall; } + int vpi_get(int code); + char* vpi_get_str(int code) { return systask_get_str(code, this); } + vpiHandle vpi_put_value(p_vpi_value val, int flags); + vpiHandle vpi_handle(int code) { return systask_handle(code, this); } + vpiHandle vpi_iterate(int code) { return systask_iter(code, this); } + + std::string return_value_; +}; + +int sysfunc_string::vpi_get(int code) +{ + switch (code) { + case vpiSize: + return return_value_.size(); + + case vpiLineNo: + return lineno; + + case vpiUserDefn: + return defn->is_user_defn; + + default: + return vpiUndefined; + } +} + +vpiHandle sysfunc_string::vpi_put_value(p_vpi_value vp, int) +{ + put_value = true; + + switch (vp->format) { + case vpiStringVal: + return_value_ = std::string(vp->value.str); + break; + default: + fprintf(stderr, "Unsupported format %d.\n", (int)vp->format); + assert(0); + } + + return 0; +} + class sysfunc_vec4 : public __vpiSysTaskCall { public: explicit inline sysfunc_vec4(unsigned wid): return_value_(wid, BIT4_X) { } @@ -845,6 +890,9 @@ vpiHandle vpip_build_vpi_call(const char*name, int val_code, unsigned return_wid } else if (val_code == -vpiVectorVal) { obj = new sysfunc_vec4(return_width); + } else if (val_code == -vpiStringVal) { + obj = new sysfunc_string; + } else if (val_code == 0 && fnet == 0) { obj = new sysfunc_no; @@ -957,11 +1005,14 @@ void vpip_execute_vpi_call(vthread_t thr, vpiHandle ref) if (vpip_cur_task->string_stack > 0) vthread_pop_str(thr, vpip_cur_task->string_stack); - /* If the function has a real value, then push the value - to the thread stack. */ + /* If the function returns a value, then push the value + to the appropriate thread stack. */ if (sysfunc_real*func_real = dynamic_cast(ref)) { vthread_push_real(thr, func_real->return_value_); } + if (sysfunc_string*func_string = dynamic_cast(ref)) { + vthread_push_str(thr, func_string->return_value_); + } if (sysfunc_vec4*func_vec4 = dynamic_cast(ref)) { vthread_push_vec4(thr, func_vec4->return_value()); } diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 032bce64c..0b1abe3f3 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -328,6 +328,11 @@ void vthread_push_real(struct vthread_s*thr, double val) thr->push_real(val); } +void vthread_push_str(struct vthread_s*thr, const string&val) +{ + thr->push_str(val); +} + void vthread_pop_vec4(struct vthread_s*thr, unsigned depth) { thr->pop_vec4(depth); diff --git a/vvp/vthread.h b/vvp/vthread.h index 7e9af3031..4df387128 100644 --- a/vvp/vthread.h +++ b/vvp/vthread.h @@ -113,6 +113,7 @@ extern vvp_context_item_t vthread_get_rd_context_item(unsigned context_idx); * Access value stacks from thread space. */ extern void vthread_push_vec4(struct vthread_s*thr, const vvp_vector4_t&val); +extern void vthread_push_str(struct vthread_s*thr, const std::string&val); extern void vthread_push_real(struct vthread_s*thr, double val); extern void vthread_pop_vec4(struct vthread_s*thr, unsigned count); From 517c9785e8004df591e5fbc000ab31d344993bef Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 9 Dec 2015 15:00:31 +0100 Subject: [PATCH 08/25] vvp: Code cleaning (vpi_tasks). --- vvp/vpi_tasks.cc | 160 ++++++++++++++++++----------------------------- 1 file changed, 61 insertions(+), 99 deletions(-) diff --git a/vvp/vpi_tasks.cc b/vvp/vpi_tasks.cc index 94df6f573..31368b391 100644 --- a/vvp/vpi_tasks.cc +++ b/vvp/vpi_tasks.cc @@ -143,54 +143,25 @@ static vpiHandle systask_iter(int, vpiHandle ref) } struct systask_def : public __vpiSysTaskCall { - inline systask_def() { } - int get_type_code(void) const { return vpiSysTaskCall; } - int vpi_get(int code) { return systask_get(code, this); } - char*vpi_get_str(int code) { return systask_get_str(code, this); } - vpiHandle vpi_handle(int code) { return systask_handle(code, this); } - vpiHandle vpi_iterate(int code){ return systask_iter(code, this); } + virtual ~systask_def() {}; + virtual int get_type_code(void) const { return vpiSysTaskCall; } + virtual int vpi_get(int code) { return systask_get(code, this); } + virtual char*vpi_get_str(int code) { return systask_get_str(code, this); } + virtual vpiHandle vpi_handle(int code) { return systask_handle(code, this); } + virtual vpiHandle vpi_iterate(int code){ return systask_iter(code, this); } }; -static vpiHandle sysfunc_put_rnet_value(vpiHandle ref, p_vpi_value vp, int) -{ - struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); +struct sysfunc_def : public systask_def { + virtual ~sysfunc_def() {}; + virtual int get_type_code(void) const { return vpiSysFuncCall; } + virtual int vpi_get(int code) { return sysfunc_get(code, this); } +}; - rfp->put_value = true; - - double val; - switch (vp->format) { - - case vpiRealVal: - val = vp->value.real; - break; - - default: - val = 0.0; - fprintf(stderr, "Unsupported format %d.\n", (int)vp->format); - assert(0); - } - - rfp->fnet->send_real(val, vthread_get_wt_context()); - - return 0; -} - -static vpiHandle sysfunc_put_no_value(vpiHandle, p_vpi_value, int) -{ - return 0; -} - -struct sysfunc_real : public __vpiSysTaskCall { - inline sysfunc_real() { } - int get_type_code(void) const { return vpiSysFuncCall; } - int vpi_get(int code) { return sysfunc_get(code, this); } - char* vpi_get_str(int code) { return systask_get_str(code, this); } +struct sysfunc_real : public sysfunc_def { vpiHandle vpi_put_value(p_vpi_value val, int flags); - vpiHandle vpi_handle(int code) - { return systask_handle(code, this); } - vpiHandle vpi_iterate(int code) - { return systask_iter(code, this); } + inline double return_value() const { return return_value_; } + private: double return_value_; }; @@ -211,19 +182,16 @@ vpiHandle sysfunc_real::vpi_put_value(p_vpi_value vp, int) return 0; } -struct sysfunc_string : public __vpiSysTaskCall { - inline sysfunc_string() { } - int get_type_code(void) const { return vpiSysFuncCall; } +struct sysfunc_str : public sysfunc_def { int vpi_get(int code); - char* vpi_get_str(int code) { return systask_get_str(code, this); } vpiHandle vpi_put_value(p_vpi_value val, int flags); - vpiHandle vpi_handle(int code) { return systask_handle(code, this); } - vpiHandle vpi_iterate(int code) { return systask_iter(code, this); } + inline const std::string& return_value() const { return return_value_; }; + private: std::string return_value_; }; -int sysfunc_string::vpi_get(int code) +int sysfunc_str::vpi_get(int code) { switch (code) { case vpiSize: @@ -240,7 +208,7 @@ int sysfunc_string::vpi_get(int code) } } -vpiHandle sysfunc_string::vpi_put_value(p_vpi_value vp, int) +vpiHandle sysfunc_str::vpi_put_value(p_vpi_value vp, int) { put_value = true; @@ -256,18 +224,11 @@ vpiHandle sysfunc_string::vpi_put_value(p_vpi_value vp, int) return 0; } -class sysfunc_vec4 : public __vpiSysTaskCall { +class sysfunc_vec4 : public sysfunc_def { public: explicit inline sysfunc_vec4(unsigned wid): return_value_(wid, BIT4_X) { } - int get_type_code(void) const { return vpiSysFuncCall; } int vpi_get(int code); - char* vpi_get_str(int code) { return systask_get_str(code, this); } vpiHandle vpi_put_value(p_vpi_value val, int flags); - vpiHandle vpi_handle(int code) - { return systask_handle(code, this); } - vpiHandle vpi_iterate(int code) - { return systask_iter(code, this); } - inline const vvp_vector4_t& return_value() const { return return_value_; } private: @@ -277,7 +238,6 @@ class sysfunc_vec4 : public __vpiSysTaskCall { vpiHandle put_value_vector_(p_vpi_value vp); vpiHandle put_value_time_(p_vpi_value vp); - private: vvp_vector4_t return_value_; }; @@ -433,48 +393,15 @@ vpiHandle sysfunc_vec4::vpi_put_value(p_vpi_value vp, int) return 0; } -struct sysfunc_4net : public __vpiSysTaskCall { +struct sysfunc_4net : public sysfunc_def { explicit inline sysfunc_4net(unsigned wid) : vwid_(wid) { } - int get_type_code(void) const { return vpiSysFuncCall; } int vpi_get(int code); - char* vpi_get_str(int code) { return systask_get_str(code, this); } vpiHandle vpi_put_value(p_vpi_value val, int flags); - vpiHandle vpi_handle(int code) - { return systask_handle(code, this); } - vpiHandle vpi_iterate(int code) - { return systask_iter(code, this); } private: unsigned vwid_; }; -struct sysfunc_rnet : public __vpiSysTaskCall { - inline sysfunc_rnet() { } - int get_type_code(void) const { return vpiSysFuncCall; } - int vpi_get(int code) { return sysfunc_get(code, this); } - char* vpi_get_str(int code) { return systask_get_str(code, this); } - vpiHandle vpi_put_value(p_vpi_value val, int flags) - { return sysfunc_put_rnet_value(this, val, flags); } - vpiHandle vpi_handle(int code) - { return systask_handle(code, this); } - vpiHandle vpi_iterate(int code) - { return systask_iter(code, this); } -}; - -struct sysfunc_no : public __vpiSysTaskCall { - inline sysfunc_no() { } - int get_type_code(void) const { return vpiSysFuncCall; } - int vpi_get(int code) { return sysfunc_get(code, this); } - char* vpi_get_str(int code) { return systask_get_str(code, this); } - vpiHandle vpi_put_value(p_vpi_value val, int flags) - { return sysfunc_put_no_value(this, val, flags); } - vpiHandle vpi_handle(int code) - { return systask_handle(code, this); } - vpiHandle vpi_iterate(int code) - { return systask_iter(code, this); } -}; - - // support getting vpiSize for a system function call int sysfunc_4net::vpi_get(int code) { @@ -592,6 +519,41 @@ vpiHandle sysfunc_4net::vpi_put_value(p_vpi_value vp, int) return 0; } +struct sysfunc_rnet : public sysfunc_def { + vpiHandle vpi_put_value(p_vpi_value val, int flags); +}; + +vpiHandle sysfunc_rnet::vpi_put_value(p_vpi_value vp, int) +{ + put_value = true; + + double value; + switch (vp->format) { + + case vpiRealVal: + value = vp->value.real; + break; + + default: + value = 0.0; + fprintf(stderr, "Unsupported format %d.\n", (int)vp->format); + assert(0); + } + + fnet->send_real(value, vthread_get_wt_context()); + + return 0; +} + +struct sysfunc_no : public sysfunc_def { + vpiHandle vpi_put_value(p_vpi_value val, int flags); +}; + +vpiHandle sysfunc_no::vpi_put_value(p_vpi_value, int) +{ + return 0; +} + /* **** Manipulate the internal data structures. **** */ @@ -891,7 +853,7 @@ vpiHandle vpip_build_vpi_call(const char*name, int val_code, unsigned return_wid obj = new sysfunc_vec4(return_width); } else if (val_code == -vpiStringVal) { - obj = new sysfunc_string; + obj = new sysfunc_str; } else if (val_code == 0 && fnet == 0) { obj = new sysfunc_no; @@ -1008,12 +970,12 @@ void vpip_execute_vpi_call(vthread_t thr, vpiHandle ref) /* If the function returns a value, then push the value to the appropriate thread stack. */ if (sysfunc_real*func_real = dynamic_cast(ref)) { - vthread_push_real(thr, func_real->return_value_); + vthread_push_real(thr, func_real->return_value()); } - if (sysfunc_string*func_string = dynamic_cast(ref)) { - vthread_push_str(thr, func_string->return_value_); + else if (sysfunc_str*func_string = dynamic_cast(ref)) { + vthread_push_str(thr, func_string->return_value()); } - if (sysfunc_vec4*func_vec4 = dynamic_cast(ref)) { + else if (sysfunc_vec4*func_vec4 = dynamic_cast(ref)) { vthread_push_vec4(thr, func_vec4->return_value()); } } From 3b310e822770ad8ec8349fd1cf26df3f9b1e01e4 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 10 Dec 2015 10:42:46 +0100 Subject: [PATCH 09/25] vhdlpp: Elaborate subprograms in packages. --- vhdlpp/architec_elaborate.cc | 6 ++++ vhdlpp/expression_elaborate.cc | 52 ++++++++++++++++++++-------------- vhdlpp/library.cc | 24 ++++++++++++++++ vhdlpp/library.h | 3 ++ vhdlpp/main.cc | 13 +++++++-- vhdlpp/package.cc | 12 ++++++++ vhdlpp/package.h | 1 + vhdlpp/std_types.h | 1 - vhdlpp/subprogram.cc | 12 ++++++++ vhdlpp/subprogram.h | 3 ++ 10 files changed, 101 insertions(+), 26 deletions(-) diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index 7430bae83..645028af0 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -21,6 +21,7 @@ # include "entity.h" # include "expression.h" # include "sequential.h" +# include "subprogram.h" # include # include @@ -59,6 +60,11 @@ int Architecture::elaborate(Entity*entity) cur->second->elaborate_init_expr(entity, this); } + // Elaborate subprograms + for (map::const_iterator cur = cur_subprograms_.begin() + ; cur != cur_subprograms_.end() ; ++cur) { + errors += cur->second->elaborate(); + } // Create 'initial' and 'final' blocks for implicit // initalization and clean-up actions if(!initializers_.empty()) diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 29a0e60b3..9c24cdc80 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -216,36 +216,44 @@ int ExpName::elaborate_lval(Entity*ent, ScopeBase*scope, bool is_sequ) const VType*found_type = 0; - if (const InterfacePort*cur = ent->find_port(name_)) { - if (cur->mode != PORT_OUT && cur->mode != PORT_INOUT) { - cerr << get_fileline() << ": error: Assignment to " - "input port " << name_ << "." << endl; - return errors += 1; - } + if (ent) { + if (const InterfacePort*cur = ent->find_port(name_)) { + if (cur->mode != PORT_OUT && cur->mode != PORT_INOUT) { + cerr << get_fileline() << ": error: Assignment to " + "input port " << name_ << "." << endl; + return errors += 1; + } - if (is_sequ) - ent->set_declaration_l_value(name_, is_sequ); + if (is_sequ) + ent->set_declaration_l_value(name_, is_sequ); - found_type = cur->type; + found_type = cur->type; - } else if (ent->find_generic(name_)) { + } else if (ent->find_generic(name_)) { - cerr << get_fileline() << ": error: Assignment to generic " - << name_ << " from entity " - << ent->get_name() << "." << endl; - return 1; + cerr << get_fileline() << ": error: Assignment to generic " + << name_ << " from entity " + << ent->get_name() << "." << endl; + return 1; + } + } - } else if (Signal*sig = scope->find_signal(name_)) { - // Tell the target signal that this may be a sequential l-value. - if (is_sequ) sig->count_ref_sequ(); + if (!found_type && scope) { + if (Signal*sig = scope->find_signal(name_)) { + // Tell the target signal that this may be a sequential l-value. + if (is_sequ) sig->count_ref_sequ(); - found_type = sig->peek_type(); + found_type = sig->peek_type(); - } else if (Variable*var = scope->find_variable(name_)) { - // Tell the target signal that this may be a sequential l-value. - if (is_sequ) var->count_ref_sequ(); + } else if (Variable*var = scope->find_variable(name_)) { + // Tell the target signal that this may be a sequential l-value. + if (is_sequ) var->count_ref_sequ(); - found_type = var->peek_type(); + found_type = var->peek_type(); + + } else if (const InterfacePort*port = scope->find_param(name_)) { + found_type = port->type; + } } if (found_type == 0) { diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index 03f0ff9df..f10b60404 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -417,3 +417,27 @@ int emit_packages(void) return 0; } + +static int elaborate_library_packages(mappackages) +{ + int errors = 0; + + for (map::iterator cur = packages.begin() + ; cur != packages.end() ; ++cur) { + errors += cur->second->elaborate(); + } + + return errors; +} + +int elaborate_libraries() +{ + int errors = 0; + + for (map::iterator cur = libraries.begin() + ; cur != libraries.end() ; ++cur) { + errors += elaborate_library_packages(cur->second.packages); + } + + return errors; +} diff --git a/vhdlpp/library.h b/vhdlpp/library.h index 68009a39a..7fb95851e 100644 --- a/vhdlpp/library.h +++ b/vhdlpp/library.h @@ -24,6 +24,9 @@ class SubprogramHeader; extern void library_set_work_path(const char*work_path); extern void library_add_directory(const char*directory); +int elaborate_libraries(void); +int emit_packages(void); + extern SubprogramHeader*library_find_subprogram(perm_string name); #endif /* IVL_library_H */ diff --git a/vhdlpp/main.cc b/vhdlpp/main.cc index 199f6e910..d6f3a51d4 100644 --- a/vhdlpp/main.cc +++ b/vhdlpp/main.cc @@ -236,20 +236,27 @@ int main(int argc, char*argv[]) return 3; } + errors = elaborate_libraries(); + if (errors > 0) { + fprintf(stderr, "%d errors elaborating libraries.\n", errors); + parser_cleanup(); + return 4; + } + emit_std_types(cout); errors = emit_packages(); if (errors > 0) { fprintf(stderr, "%d errors emitting packages.\n", errors); parser_cleanup(); - return 4; + return 5; } errors = emit_entities(); if (errors > 0) { fprintf(stderr, "%d errors emitting design.\n", errors); - parser_cleanup(); - return 4; + parser_cleanup(); + return 6; } parser_cleanup(); diff --git a/vhdlpp/package.cc b/vhdlpp/package.cc index 64d20fc80..40730f026 100644 --- a/vhdlpp/package.cc +++ b/vhdlpp/package.cc @@ -41,6 +41,18 @@ void Package::set_library(perm_string lname) from_library_ = lname; } +int Package::elaborate() +{ + int errors = 0; + + for (map::const_iterator cur = cur_subprograms_.begin() + ; cur != cur_subprograms_.end() ; ++cur) { + errors += cur->second->elaborate(); + } + + return errors; +} + /* * The Package::write_to_stream is used to write the package to the * work space (or library) so writes proper VHDL that the library diff --git a/vhdlpp/package.h b/vhdlpp/package.h index fb6bfb8ac..3f75c8820 100644 --- a/vhdlpp/package.h +++ b/vhdlpp/package.h @@ -42,6 +42,7 @@ class Package : public Scope, public LineInfo { void write_to_stream(std::ostream&fd) const; int emit_package(std::ostream&fd) const; + int elaborate(); private: perm_string from_library_; diff --git a/vhdlpp/std_types.h b/vhdlpp/std_types.h index 033ac2167..b00dd503f 100644 --- a/vhdlpp/std_types.h +++ b/vhdlpp/std_types.h @@ -23,7 +23,6 @@ class ActiveScope; void emit_std_types(ostream&out); -int emit_packages(void); void generate_global_types(ActiveScope*res); bool is_global_type(perm_string type_name); void delete_global_types(); diff --git a/vhdlpp/subprogram.cc b/vhdlpp/subprogram.cc index 59862f97d..80839b557 100644 --- a/vhdlpp/subprogram.cc +++ b/vhdlpp/subprogram.cc @@ -53,6 +53,18 @@ void SubprogramBody::set_statements(list*stmt) statements_ = stmt; } +int SubprogramBody::elaborate() +{ + int errors = 0; + + for (list::const_iterator cur = statements_->begin() + ; cur != statements_->end() ; ++cur) { + errors += (*cur)->elaborate(0, this); + } + + return errors; +} + void SubprogramBody::write_to_stream(ostream&fd) const { for (map::const_iterator cur = new_variables_.begin() diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h index 6972ae0be..a07570fac 100644 --- a/vhdlpp/subprogram.h +++ b/vhdlpp/subprogram.h @@ -45,6 +45,7 @@ class SubprogramBody : public LineInfo, public ScopeBase { void set_statements(std::list*statements); inline bool empty_statements() const { return !statements_ || statements_->empty(); } + int elaborate(); int emit(ostream&out, Entity*ent, ScopeBase*scope); // Emit body as it would show up in a package. @@ -89,6 +90,8 @@ class SubprogramHeader : public LineInfo { inline perm_string name() const { return name_; } + int elaborate() { return (body_ ? body_->elaborate() : 0); } + // Function name used in the emission step. The main purpose of this // method is to handle functions offered by standard VHDL libraries. // Allows to return different function names depending on the arguments From 9276515e1964a63b1be7c6d12f02cb6459226834 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 10 Dec 2015 10:42:59 +0100 Subject: [PATCH 10/25] vhdlpp: Minor fix for ReportStmt::write_to_stream. --- vhdlpp/sequential_emit.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index c5309c039..2f09ad0a6 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -524,9 +524,8 @@ int ReportStmt::emit(ostream&out, Entity*ent, ScopeBase*scope) void ReportStmt::write_to_stream(std::ostream&fd) { - fd << "report \""; + fd << "report "; msg_->write_to_stream(fd); - fd << "\"" << std::endl; fd << "severity "; switch(severity_) From 1d2aef714237dc1f55d97407032c1903ccd449a2 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 11 Dec 2015 12:58:25 +0100 Subject: [PATCH 11/25] vpi: $sformatf() function. --- vpi/sys_display.c | 82 +++++++++++++++++++++++++++++++++++++++++------ vpi/system.sft | 2 ++ 2 files changed, 75 insertions(+), 9 deletions(-) diff --git a/vpi/sys_display.c b/vpi/sys_display.c index a7a34dfa7..c65c1b14d 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -169,10 +169,11 @@ static int get_default_format(const char *name) int default_format; switch(name[ strlen(name)-1 ]){ - /* writE/strobE or monitoR or displaY/fdisplaY or sformaT */ + /* writE/strobE or monitoR or displaY/fdisplaY or sformaT/sformatF */ case 'e': case 'r': case 't': + case 'f': case 'y': default_format = vpiDecStrVal; break; case 'h': default_format = vpiHexStrVal; break; case 'o': default_format = vpiOctStrVal; break; @@ -1238,7 +1239,8 @@ static PLI_INT32 sys_display_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) return sys_common_compiletf(name, 0, 0); } -/* This implements the $display/$fdisplay and the $write/$fwrite based tasks. */ +/* This implements the $sformatf, $display/$fdisplay + * and the $write/$fwrite based tasks. */ static PLI_INT32 sys_display_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) { vpiHandle callh, argv, scope; @@ -1246,6 +1248,7 @@ static PLI_INT32 sys_display_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) char* result; unsigned int size; PLI_UINT32 fd_mcd; + s_vpi_value val; callh = vpi_handle(vpiSysTfCall, 0); argv = vpi_iterate(vpiArgument, callh); @@ -1254,7 +1257,6 @@ static PLI_INT32 sys_display_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) if(name[1] == 'f') { errno = 0; vpiHandle arg = vpi_scan(argv); - s_vpi_value val; val.format = vpiIntVal; vpi_get_value(arg, &val); fd_mcd = val.value.integer; @@ -1275,7 +1277,11 @@ static PLI_INT32 sys_display_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) vpi_free_object(argv); return 0; } + } else if(strncmp(name,"$sformatf",9) == 0) { + /* return as a string */ + fd_mcd = 0; } else { + /* stdout */ fd_mcd = 1; } @@ -1293,13 +1299,21 @@ static PLI_INT32 sys_display_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) /* Because %u and %z may put embedded NULL characters into the * returned string strlen() may not match the real size! */ result = get_display(&size, &info); - my_mcd_rawwrite(fd_mcd, result, size); - if ((strncmp(name,"$display",8) == 0) || - (strncmp(name,"$fdisplay",9) == 0)) my_mcd_rawwrite(fd_mcd, "\n", 1); + if(fd_mcd > 0) { + my_mcd_rawwrite(fd_mcd, result, size); + if ((strncmp(name,"$display",8) == 0) || + (strncmp(name,"$fdisplay",9) == 0)) my_mcd_rawwrite(fd_mcd, "\n", 1); + } else { + /* Return as a string ($sformatf) */ + val.format = vpiStringVal; + val.value.str = result; + vpi_put_value(callh, &val, 0, vpiNoDelay); + } + + free(result); free(info.filename); free(info.items); - free(result); return 0; } @@ -1665,7 +1679,7 @@ static PLI_INT32 sys_sformat_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) if (argv == 0) { vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s requires at least two argument.\n", name); + vpi_printf("%s requires at least two arguments.\n", name); vpi_control(vpiFinish, 1); return 0; } @@ -1686,7 +1700,7 @@ static PLI_INT32 sys_sformat_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) if (arg == 0) { vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s requires at least two argument.\n", name); + vpi_printf("%s requires at least two arguments.\n", name); vpi_control(vpiFinish, 1); return 0; } @@ -1754,6 +1768,46 @@ static PLI_INT32 sys_sformat_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) return 0; } +static PLI_INT32 sys_sformatf_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle arg; + PLI_INT32 type; + + /* Check that there are arguments. */ + if (argv == 0) { + vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s requires at least one argument.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + + /* The first argument must be a string, a register or a SV string. */ + arg = vpi_scan(argv); + if (arg == 0) { + vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s requires at least one argument.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + type = vpi_get(vpiType, arg); + if (((type != vpiConstant && type != vpiParameter) || + vpi_get(vpiConstType, arg) != vpiStringConst) && + type != vpiReg && type != vpiStringVar) { + vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s's first argument must be a string or a register.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + + if (sys_check_args(callh, argv, name, 0, 0)) vpi_control(vpiFinish, 1); + return 0; +} + static PLI_INT32 sys_end_of_compile(p_cb_data cb_data) { (void)cb_data; /* Parameter is not used. */ @@ -2434,6 +2488,16 @@ void sys_display_register(void) res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiStringFunc; + tf_data.tfname = "$sformatf"; + tf_data.calltf = sys_display_calltf; + tf_data.compiletf = sys_sformatf_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$sformatf"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); + /*============================ timeformat */ tf_data.type = vpiSysTask; tf_data.tfname = "$timeformat"; diff --git a/vpi/system.sft b/vpi/system.sft index f3048198f..be082c85f 100644 --- a/vpi/system.sft +++ b/vpi/system.sft @@ -24,3 +24,5 @@ $table_model vpiSysFuncReal $ivl_string_method$len vpiSysFuncInt $ivl_string_method$to_vec vpiSysFuncVoid + +$sformatf vpiSysFuncString From 40075e11ab18abf53ef6dddae5034b2b5c78f490 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 14 Dec 2015 12:02:59 +0100 Subject: [PATCH 12/25] Code formatting. --- vhdlpp/expression_elaborate.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 9c24cdc80..de5b9c598 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -920,31 +920,31 @@ const VType* ExpName::probe_type(Entity*ent, ScopeBase*scope) const if(ent) { if (const InterfacePort*cur = ent->find_port(name_)) { - ivl_assert(*this, cur->type); - return cur->type; + ivl_assert(*this, cur->type); + return cur->type; } if (const InterfacePort*cur = ent->find_generic(name_)) { - ivl_assert(*this, cur->type); - return cur->type; + ivl_assert(*this, cur->type); + return cur->type; } } if(scope) { if (Signal*sig = scope->find_signal(name_)) - return sig->peek_type(); + return sig->peek_type(); if (Variable*var = scope->find_variable(name_)) - return var->peek_type(); + return var->peek_type(); const VType*type = 0; Expression*cval = 0; if (scope->find_constant(name_, type, cval)) - return type; + return type; Architecture*arc = dynamic_cast(scope); if (arc && (type = arc->probe_genvar_type(name_))) { - return type; + return type; } if (const InterfacePort*port = scope->find_param(name_)) { From 23633c498f290905f60842ff8da045fefe0118ee Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 14 Dec 2015 13:17:36 +0100 Subject: [PATCH 13/25] vhdlpp: Moved dump_scope() to ScopeBase class. --- vhdlpp/debug.cc | 2 +- vhdlpp/scope.h | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index 22fb312a6..dfa44257d 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -101,7 +101,7 @@ void ComponentBase::dump_ports(ostream&out, int indent) const } } -void Scope::dump_scope(ostream&out) const +void ScopeBase::dump_scope(ostream&out) const { // Dump types out << " -- imported types" << endl; diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index 444583d09..df1f1daba 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -90,6 +90,8 @@ class ScopeBase { finalizers_.push_back(s); } + void dump_scope(ostream&out) const; + protected: void cleanup(); @@ -154,9 +156,6 @@ class Scope : public ScopeBase { ComponentBase* find_component(perm_string by_name); - public: - void dump_scope(ostream&out) const; - protected: // Helper method for emitting signals in the scope. int emit_signals(ostream&out, Entity*ent, Architecture*arc); From 2c010d34bb9c6cdcf7e19f147f8a2029f7dca502 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 14 Dec 2015 14:36:23 +0100 Subject: [PATCH 14/25] vhdlpp: Unified Expression::evaluate() method. --- vhdlpp/expression.cc | 10 +- vhdlpp/expression.h | 18 ++-- vhdlpp/expression_elaborate.cc | 7 +- vhdlpp/expression_emit.cc | 2 +- vhdlpp/expression_evaluate.cc | 188 +++++++++++---------------------- 5 files changed, 77 insertions(+), 148 deletions(-) diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index baa0ce554..52b77439e 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -88,14 +88,14 @@ ExpBinary::~ExpBinary() delete operand2_; } -bool ExpBinary::eval_operand1(ScopeBase*scope, int64_t&val) const +bool ExpBinary::eval_operand1(Entity*ent, ScopeBase*scope, int64_t&val) const { - return operand1_->evaluate(scope, val); + return operand1_->evaluate(ent, scope, val); } -bool ExpBinary::eval_operand2(ScopeBase*scope, int64_t&val) const +bool ExpBinary::eval_operand2(Entity*ent, ScopeBase*scope, int64_t&val) const { - return operand2_->evaluate(scope, val); + return operand2_->evaluate(ent, scope, val); } void ExpBinary::visit(ExprVisitor& func) @@ -493,7 +493,7 @@ ExpInteger::~ExpInteger() { } -bool ExpInteger::evaluate(ScopeBase*, int64_t&val) const +bool ExpInteger::evaluate(Entity*, ScopeBase*, int64_t&val) const { val = value_; return true; diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index eb83474df..45ba5f9ec 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -107,8 +107,8 @@ class Expression : public LineInfo { // to constant literal values. Return true and set the val // argument if the evaluation works, or return false if it // cannot be done. - virtual bool evaluate(ScopeBase*scope, int64_t&val) const; - virtual bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; + virtual bool evaluate(Entity*, ScopeBase*, int64_t&) const { return false; } + bool evaluate(ScopeBase*scope, int64_t&val) const { return evaluate(NULL, scope, val); } // The symbolic compare returns true if the two expressions // are equal without actually calculating the value. @@ -205,8 +205,8 @@ class ExpBinary : public Expression { int emit_operand1(ostream&out, Entity*ent, ScopeBase*scope); int emit_operand2(ostream&out, Entity*ent, ScopeBase*scope); - bool eval_operand1(ScopeBase*scope, int64_t&val) const; - bool eval_operand2(ScopeBase*scope, int64_t&val) const; + bool eval_operand1(Entity*ent, ScopeBase*scope, int64_t&val) const; + bool eval_operand2(Entity*ent, ScopeBase*scope, int64_t&val) const; inline void write_to_stream_operand1(std::ostream&out) const { operand1_->write_to_stream(out); } @@ -343,7 +343,7 @@ class ExpArithmetic : public ExpBinary { int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&fd) const; int emit(ostream&out, Entity*ent, ScopeBase*scope); - virtual bool evaluate(ScopeBase*scope, int64_t&val) const; + virtual bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; private: @@ -369,7 +369,6 @@ class ExpAttribute : public Expression { void write_to_stream(std::ostream&fd) const; int emit(ostream&out, Entity*ent, ScopeBase*scope); // Some attributes can be evaluated at compile time - bool evaluate(ScopeBase*scope, int64_t&val) const; bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; void visit(ExprVisitor& func); @@ -440,7 +439,6 @@ class ExpConcat : public Expression { int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&fd) const; int emit(ostream&out, Entity*ent, ScopeBase*scope); - virtual bool evaluate(ScopeBase*scope, int64_t&val) const; bool is_primary(void) const; void dump(ostream&out, int indent = 0) const; void visit(ExprVisitor& func); @@ -583,7 +581,7 @@ class ExpInteger : public Expression { int emit(ostream&out, Entity*ent, ScopeBase*scope); int emit_package(std::ostream&out); bool is_primary(void) const { return true; } - bool evaluate(ScopeBase*scope, int64_t&val) const; + bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; virtual ostream& dump_inline(ostream&out) const; @@ -665,7 +663,6 @@ class ExpName : public Expression { void write_to_stream(std::ostream&fd) const; int emit(ostream&out, Entity*ent, ScopeBase*scope); bool is_primary(void) const; - bool evaluate(ScopeBase*scope, int64_t&val) const; bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; bool symbolic_compare(const Expression*that) const; void dump(ostream&out, int indent = 0) const; @@ -773,7 +770,7 @@ class ExpShift : public ExpBinary { int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&fd) const; int emit(ostream&out, Entity*ent, ScopeBase*scope); - virtual bool evaluate(ScopeBase*scope, int64_t&val) const; + bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; private: @@ -891,7 +888,6 @@ class ExpTime : public Expression { int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&) const; int emit(ostream&out, Entity*ent, ScopeBase*scope); - //bool evaluate(ScopeBase*scope, int64_t&val) const; //bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index de5b9c598..f7b3d055b 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -57,7 +57,8 @@ const VType* Expression::fit_type(Entity*ent, ScopeBase*scope, const VTypeArray* return res; } -const VType*ExpName::elaborate_adjust_type_with_range_(Entity*, ScopeBase*scope, const VType*type) +const VType*ExpName::elaborate_adjust_type_with_range_(Entity*ent, ScopeBase*scope, + const VType*type) { // Unfold typedefs while (const VTypeDef*tdef = dynamic_cast(type)) { @@ -76,9 +77,9 @@ const VType*ExpName::elaborate_adjust_type_with_range_(Entity*, ScopeBase*scope, int64_t use_msb, use_lsb; bool flag; - flag = index_->evaluate(scope, use_msb); + flag = index_->evaluate(ent, scope, use_msb); ivl_assert(*this, flag); - flag = lsb_->evaluate(scope, use_lsb); + flag = lsb_->evaluate(ent, scope, use_lsb); ivl_assert(*this, flag); type = new VTypeArray(array->element_type(), use_msb, use_lsb); diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 41436a933..1623037cf 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -337,7 +337,7 @@ int ExpAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope) // Try to evaluate first int64_t val; - if(evaluate(scope, val)) { + if(evaluate(ent, scope, val)) { out << val; return 0; } diff --git a/vhdlpp/expression_evaluate.cc b/vhdlpp/expression_evaluate.cc index 0d7ef1634..b88e40032 100644 --- a/vhdlpp/expression_evaluate.cc +++ b/vhdlpp/expression_evaluate.cc @@ -25,26 +25,16 @@ # include # include -bool Expression::evaluate(ScopeBase*, int64_t&) const -{ - return false; -} - -bool Expression::evaluate(Entity*, ScopeBase*scope, int64_t&val) const -{ - return evaluate(scope, val); -} - -bool ExpArithmetic::evaluate(ScopeBase*scope, int64_t&val) const +bool ExpArithmetic::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const { int64_t val1, val2; bool rc; - rc = eval_operand1(scope, val1); + rc = eval_operand1(ent, scope, val1); if (rc == false) return false; - rc = eval_operand2(scope, val2); + rc = eval_operand2(ent, scope, val2); if (rc == false) return false; @@ -83,151 +73,97 @@ bool ExpArithmetic::evaluate(ScopeBase*scope, int64_t&val) const return true; } -bool ExpAttribute::evaluate(ScopeBase*scope, int64_t&val) const -{ - /* Special Case: The array attributes can sometimes be calculated all - the down to a literal integer at compile time, and all it - needs is the type of the base expression. (The base - expression doesn't even need to be evaluated.) */ - if (name_ == "length" || name_ == "right" || name_ == "left") { - const VType*base_type = base_->peek_type(); - - if(!base_type) { - const ExpName*name = NULL; - - if(scope && (name = dynamic_cast(base_))) { - const perm_string& n = name->peek_name(); - if(const Variable*var = scope->find_variable(n)) - base_type = var->peek_type(); - else if(const Signal*sig = scope->find_signal(n)) - base_type = sig->peek_type(); - else if(const InterfacePort*port = scope->find_param(n)) - base_type = port->type; - } - } - - if(!base_type) - return false; // I tried really hard, sorry - - const VTypeArray*arr = dynamic_cast(base_type); - if (arr == 0) { - cerr << endl << get_fileline() << ": error: " - << "Cannot apply the '" << name_ << " attribute to non-array objects" - << endl; - ivl_assert(*this, false); - return false; - } - - if(name_ == "length") { - int64_t size = arr->get_width(scope); - - if(size > 0) - val = size; - else - return false; - } else if(name_ == "left") { - arr->dimension(0).msb()->evaluate(scope, val); - } else if(name_ == "right") { - arr->dimension(0).lsb()->evaluate(scope, val); - } else ivl_assert(*this, false); - - return true; - } - - return false; -} - bool ExpAttribute::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const { - if (!ent || !scope) { // it's impossible to evaluate, probably it is inside a subprogram - return false; - } + const VType*base_type = base_->peek_type(); + + if (base_type == NULL) + base_type = base_->probe_type(ent, scope); + + if (base_type == NULL) + return false; if (name_ == "left" || name_ == "right") { - const VType*base_type = base_->peek_type(); - if (base_type == 0) - base_type = base_->probe_type(ent, scope); - - ivl_assert(*this, base_type); - const VTypeArray*arr = dynamic_cast(base_type); - if (arr == 0) { + if (arr == NULL) { cerr << endl << get_fileline() << ": error: " << "Cannot apply the '" << name_ << " attribute to non-array objects" << endl; - ivl_assert(*this, false); return false; } - ivl_assert(*this, arr->dimensions() == 1); - if(name_ == "left") - arr->dimension(0).msb()->evaluate(ent, scope, val); - else // "right" - arr->dimension(0).lsb()->evaluate(ent, scope, val); + if (arr->dimensions() != 1) { + cerr << endl << get_fileline() << ": error: " + << "Cannot apply the '" << name_ + << " attribute to multidimensional arrays" << endl; + return false; + } - return true; + if (arr->dimension(0).is_box()) + return false; + + if (name_ == "left") { + return arr->dimension(0).msb()->evaluate(ent, scope, val); + } else if (name_ == "right") { + return arr->dimension(0).lsb()->evaluate(ent, scope, val); + } else { + ivl_assert(*this, false); + } } - return evaluate(scope, val); -} + else if (name_ == "length") { + int64_t size = base_type->get_width(scope); + + if (size > 0) { + val = size; + return true; + } + } -/* - * I don't yet know how to evaluate concatenations. It is not likely - * to come up anyhow. - */ -bool ExpConcat::evaluate(ScopeBase*, int64_t&) const -{ return false; } -bool ExpName::evaluate(ScopeBase*scope, int64_t&val) const -{ - const VType*type; - Expression*exp; - - if (prefix_.get()) { - cerr << get_fileline() << ": sorry: I don't know how to evaluate ExpName prefix parts." << endl; - return false; - } - - if (!scope) - return false; - - if (!scope->find_constant(name_, type, exp)) - return false; - - return exp->evaluate(scope, val); -} - bool ExpName::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const { if (prefix_.get()) { - cerr << get_fileline() << ": sorry: I don't know how to evaluate ExpName prefix parts." << endl; - return false; + cerr << get_fileline() << ": sorry: I don't know how to evaluate " + << "ExpName prefix parts." << endl; + return false; } - const InterfacePort*gen = ent->find_generic(name_); - if (gen) { - cerr << get_fileline() << ": sorry: I don't necessarily handle generic overrides." << endl; + if (ent) { + const InterfacePort*gen = ent->find_generic(name_); + if (gen) { + cerr << get_fileline() << ": sorry: I don't necessarily " + << "handle generic overrides." << endl; - // Evaluate the default expression and use that. - if (gen->expr) - return gen->expr->evaluate(ent, scope, val); + // Evaluate the default expression and use that. + if (gen->expr) + return gen->expr->evaluate(ent, scope, val); + } } - return evaluate(scope, val); + if (scope) { + const VType*type; + Expression*exp; + + if (scope->find_constant(name_, type, exp)) + return exp->evaluate(ent, scope, val); + } + + return false; } -bool ExpShift::evaluate(ScopeBase*scope, int64_t&val) const +bool ExpShift::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const { int64_t val1, val2; bool rc; - rc = eval_operand1(scope, val1); + rc = eval_operand1(ent, scope, val1); if (rc == false) return false; - rc = eval_operand2(scope, val2); + rc = eval_operand2(ent, scope, val2); if (rc == false) return false; @@ -252,7 +188,7 @@ bool ExpShift::evaluate(ScopeBase*scope, int64_t&val) const return true; } -/*bool ExpTime::evaluate(ScopeBase*, int64_t&val) const +/*bool ExpTime::evaluate(Entity*, ScopeBase*, int64_t&val) const { double v = to_fs(); @@ -265,8 +201,4 @@ bool ExpShift::evaluate(ScopeBase*scope, int64_t&val) const val = v; return true; } - -bool ExpTime::evaluate(Entity*, ScopeBase*, int64_t&val) const -{ - return evaluate(NULL, val); }*/ From e0b2a5b337c8882621b1bcab97ee5ba28cb5a82e Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 15 Dec 2015 18:13:33 +0100 Subject: [PATCH 15/25] vhdlpp: Refactored prange_t (class ExpRange). --- vhdlpp/architec.cc | 2 +- vhdlpp/architec.h | 4 +- vhdlpp/debug.cc | 7 --- vhdlpp/expression.cc | 78 ++++++++++++++++++++++++++++++++-- vhdlpp/expression.h | 55 +++++++++++++++++++++--- vhdlpp/expression_debug.cc | 6 +++ vhdlpp/expression_elaborate.cc | 19 +++++++-- vhdlpp/expression_emit.cc | 24 ++++++++++- vhdlpp/expression_stream.cc | 26 +++++++++--- vhdlpp/parse.y | 45 +++++++++----------- vhdlpp/parse_misc.cc | 14 +++--- vhdlpp/parse_misc.h | 6 +-- vhdlpp/parse_types.h | 29 ------------- vhdlpp/sequential.cc | 2 +- vhdlpp/sequential.h | 4 +- vhdlpp/sequential_emit.cc | 65 ++++++++++------------------ vhdlpp/vtype.cc | 13 +++--- vhdlpp/vtype.h | 4 +- 18 files changed, 253 insertions(+), 150 deletions(-) diff --git a/vhdlpp/architec.cc b/vhdlpp/architec.cc index 57b885feb..2f1cea235 100644 --- a/vhdlpp/architec.cc +++ b/vhdlpp/architec.cc @@ -137,7 +137,7 @@ GenerateStatement::~GenerateStatement() } ForGenerate::ForGenerate(perm_string gname, perm_string genvar, - prange_t*rang, std::list&s) + ExpRange*rang, std::list&s) : GenerateStatement(gname, s), genvar_(genvar), lsb_(rang->lsb()), msb_(rang->msb()) { diff --git a/vhdlpp/architec.h b/vhdlpp/architec.h index 435ad3639..d33a33e57 100644 --- a/vhdlpp/architec.h +++ b/vhdlpp/architec.h @@ -33,7 +33,7 @@ class GenerateStatement; class SequentialStmt; class Signal; class named_expr_t; -class prange_t; +class ExpRange; /* * The Architecture class carries the contents (name, statements, @@ -142,7 +142,7 @@ class ForGenerate : public GenerateStatement { public: ForGenerate(perm_string gname, perm_string genvar, - prange_t*rang, std::list&s); + ExpRange*rang, std::list&s); ~ForGenerate(); int elaborate(Entity*ent, Architecture*arc); diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index dfa44257d..f3dbc4b55 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -442,13 +442,6 @@ void named_expr_t::dump(ostream&out, int indent) const expr_->dump(out, indent); } -void prange_t::dump(ostream&out, int indent) const -{ - left_->dump(out, indent); - out << setw(indent) << "" << (direction_ ? "downto" : "to"); - right_->dump(out, indent); -} - ostream& Expression::dump_inline(ostream&out) const { out << typeid(*this).name(); diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index 52b77439e..72d4c4435 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -77,6 +77,9 @@ void ExpAttribute::visit(ExprVisitor& func) func(this); } +const perm_string ExpAttribute::LEFT = perm_string::literal("left"); +const perm_string ExpAttribute::RIGHT = perm_string::literal("right"); + ExpBinary::ExpBinary(Expression*op1, Expression*op2) : operand1_(op1), operand2_(op2) { @@ -192,7 +195,7 @@ ExpAggregate::choice_t::choice_t() { } -ExpAggregate::choice_t::choice_t(prange_t*rang) +ExpAggregate::choice_t::choice_t(ExpRange*rang) : range_(rang) { } @@ -203,7 +206,7 @@ ExpAggregate::choice_t::choice_t(const choice_t&other) expr_.reset(e->clone()); if(other.range_.get()) - range_.reset(new prange_t(*other.range_.get())); + range_.reset(static_cast(other.range_.get()->clone())); } ExpAggregate::choice_t::~choice_t() @@ -221,7 +224,7 @@ Expression*ExpAggregate::choice_t::simple_expression(bool detach_flag) return res; } -prange_t*ExpAggregate::choice_t::range_expressions(void) +ExpRange*ExpAggregate::choice_t::range_expressions(void) { return range_.get(); } @@ -535,6 +538,7 @@ ExpName::ExpName(perm_string nn, list*indices) ExpName::ExpName(perm_string nn, Expression*msb, Expression*lsb) : name_(nn), index_(msb), lsb_(lsb) { + ivl_assert(*this, !msb || msb != lsb); } ExpName::ExpName(ExpName*prefix, perm_string nn) @@ -545,6 +549,7 @@ ExpName::ExpName(ExpName*prefix, perm_string nn) ExpName::ExpName(ExpName*prefix, perm_string nn, Expression*msb, Expression*lsb) : prefix_(prefix), name_(nn), index_(msb), lsb_(lsb) { + ivl_assert(*this, !msb || msb != lsb); } ExpName::~ExpName() @@ -712,3 +717,70 @@ double ExpTime::to_fs() const return val; } + +ExpRange::ExpRange(Expression*left, Expression*right, range_dir_t direction) +: left_(left), right_(right), direction_(direction), range_expr_(false) +{ +} + +ExpRange::ExpRange(ExpName*base, bool reverse_range) +: direction_(AUTO), range_expr_(true), range_base_(base), range_reverse_(reverse_range) +{ +} + +ExpRange::~ExpRange() +{ + delete left_; + delete right_; + delete range_base_; +} + +Expression*ExpRange::clone() const +{ + if(range_expr_) + return new ExpRange(static_cast(range_base_->clone()), range_reverse_); + else + return new ExpRange(left_->clone(), right_->clone(), direction_); +} + +Expression* ExpRange::msb() +{ + ivl_assert(*this, direction() != AUTO); + + switch(direction()) { + case DOWNTO: return left_; + case TO: return right_; + default: return NULL; + } + + return NULL; +} + +Expression* ExpRange::lsb() +{ + ivl_assert(*this, direction() != AUTO); + + switch(direction()) { + case DOWNTO: return right_; + case TO: return left_; + default: return NULL; + } + + return NULL; +} + +Expression*ExpRange::left() +{ + if(range_expr_ && !left_) + left_ = new ExpAttribute(range_base_, ExpAttribute::LEFT); + + return left_; +} + +Expression*ExpRange::right() +{ + if(range_expr_ && !right_) + right_ = new ExpAttribute(range_base_, ExpAttribute::RIGHT); + + return right_; +} diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index 45ba5f9ec..e9513b31e 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -29,8 +29,7 @@ # include # include -class prange_t; -class Entity; +class ExpRange; class ScopeBase; class SubprogramHeader; class VType; @@ -239,7 +238,7 @@ class ExpAggregate : public Expression { // Create a named choice explicit choice_t(perm_string name); // discreate_range choice - explicit choice_t(prange_t*ran); + explicit choice_t(ExpRange*ran); choice_t(const choice_t&other); @@ -249,15 +248,15 @@ class ExpAggregate : public Expression { bool others() const; // Return expression if this represents a simple_expression. Expression*simple_expression(bool detach_flag =true); - // Return prange_t if this represents a range_expression - prange_t*range_expressions(void); + // Return ExpRange if this represents a range_expression + ExpRange*range_expressions(void); void write_to_stream(std::ostream&fd); void dump(ostream&out, int indent) const; private: std::auto_ptrexpr_; - std::auto_ptr range_; + std::auto_ptr range_; private: // not implemented choice_t& operator= (const choice_t&); }; @@ -373,6 +372,10 @@ class ExpAttribute : public Expression { void dump(ostream&out, int indent = 0) const; void visit(ExprVisitor& func); + // Constants for the standard attributes + static const perm_string LEFT; + static const perm_string RIGHT; + private: ExpName*base_; perm_string name_; @@ -898,6 +901,46 @@ class ExpTime : public Expression { timeunit_t unit_; }; +class ExpRange : public Expression { + public: + typedef enum { DOWNTO, TO, AUTO } range_dir_t; + + // Regular range + ExpRange(Expression*left, Expression*right, range_dir_t direction); + // 'range/'reverse range attribute + ExpRange(ExpName*base, bool reverse_range); + ~ExpRange(); + + Expression*clone() const; + + // Returns the upper boundary + Expression*msb(); + // Returns the lower boundary + Expression*lsb(); + + Expression*left(); + Expression*right(); + + range_dir_t direction() const { return direction_; } + + int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); + void write_to_stream(std::ostream&) const; + int emit(ostream&out, Entity*ent, ScopeBase*scope); + void dump(ostream&out, int indent = 0) const; + private: + // Regular range related fields + Expression*left_, *right_; + range_dir_t direction_; + + // 'range/'reverse_range attribute related fields + // Flag to indicate it is a 'range/'reverse_range expression + bool range_expr_; + // Object name to which the attribute is applied + ExpName*range_base_; + // Flag to distinguish between 'range & 'reverse_range + bool range_reverse_; +}; + // Elaborates an expression used as an argument in a procedure/function call. int elaborate_argument(Expression*expr, const SubprogramHeader*subp, int idx, Entity*ent, ScopeBase*scope); diff --git a/vhdlpp/expression_debug.cc b/vhdlpp/expression_debug.cc index fd52b6875..c2bc38125 100644 --- a/vhdlpp/expression_debug.cc +++ b/vhdlpp/expression_debug.cc @@ -117,3 +117,9 @@ void ExpTime::dump(ostream&out, int indent) const out << setw(indent) << "" << "Time "; write_to_stream(out); } + +void ExpRange::dump(ostream&out, int indent) const +{ + out << setw(indent) << "" << "Range "; + write_to_stream(out); +} diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index f7b3d055b..0ca07f0d7 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -402,7 +402,7 @@ const VType*ExpAggregate::fit_type(Entity*, ScopeBase*, const VTypeArray*host) c elements_[0]->map_choices(&ce[0]); ivl_assert(*this, ce.size() == 1); - prange_t*prange = ce[0].choice->range_expressions(); + ExpRange*prange = ce[0].choice->range_expressions(); ivl_assert(*this, prange); Expression*use_msb = prange->msb(); @@ -657,8 +657,8 @@ const VType*ExpConcat::fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*at new ExpArithmetic(ExpArithmetic::PLUS, sizes[0], sizes[1]), new ExpInteger(1)); - std::list ranges; - ranges.push_front(new prange_t(size, new ExpInteger(0), true)); + std::list ranges; + ranges.push_front(new ExpRange(size, new ExpInteger(0), ExpRange::DOWNTO)); const VType*array = new VTypeArray(types[1], &ranges); return array; @@ -1057,6 +1057,19 @@ int ExpTime::elaborate_expr(Entity*, ScopeBase*, const VType*) return 0; } +int ExpRange::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) +{ + int errors = 0; + + if(left_) + errors += left_->elaborate_expr(ent, scope, &primitive_INTEGER); + + if(right_) + errors += right_->elaborate_expr(ent, scope, &primitive_INTEGER); + + return errors; +} + int elaborate_argument(Expression*expr, const SubprogramHeader*subp, int idx, Entity*ent, ScopeBase*scope) { diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 1623037cf..223f4e9ea 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -224,7 +224,7 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, ScopeBase*scope, const VT // If this is a range choice, then calculate the bounds // of the range and scan through the values, mapping the // value to the aggregate_[idx] element. - if (prange_t*range = aggregate_[idx].choice->range_expressions()) { + if (ExpRange*range = aggregate_[idx].choice->range_expressions()) { int64_t begin_val, end_val; if (! range->msb()->evaluate(ent, scope, begin_val)) { @@ -1031,3 +1031,25 @@ int ExpTime::emit(ostream&out, Entity*, ScopeBase*) return 0; } + +int ExpRange::emit(ostream&out, Entity*ent, ScopeBase*scope) +{ + int errors = 0; + + if(range_expr_) { + out << "$left("; + errors += range_base_->emit(out, ent, scope); + out << "):$right("; + errors += range_base_->emit(out, ent, scope); + out << ")"; + } else if(direction_ == AUTO) { + ivl_assert(*this, false); + out << "/* auto dir */"; + } else { + errors += left_->emit(out, ent, scope); + out << ":"; + errors += right_->emit(out, ent, scope); + } + + return 0; +} diff --git a/vhdlpp/expression_stream.cc b/vhdlpp/expression_stream.cc index d707fdcff..059ba80de 100644 --- a/vhdlpp/expression_stream.cc +++ b/vhdlpp/expression_stream.cc @@ -61,13 +61,9 @@ void ExpAggregate::choice_t::write_to_stream(ostream&fd) return; } - if (prange_t*rp = range_expressions()) { - rp->msb()->write_to_stream(fd); - if (rp->is_downto()) - fd << " downto "; - else - fd << " to "; - rp->msb()->write_to_stream(fd); + if (ExpRange*rp = range_expressions()) { + rp->write_to_stream(fd); + return; } fd << "/* ERROR */"; @@ -316,3 +312,19 @@ void ExpTime::write_to_stream(ostream&fd) const case S: fd << " s"; break; } } + +void ExpRange::write_to_stream(ostream&fd) const +{ + if(range_expr_) { + range_base_->write_to_stream(fd); + fd << (range_reverse_ ? "'reverse_range" : "'range"); + } else { + left_->write_to_stream(fd); + switch(direction_) { + case DOWNTO: fd << " downto "; break; + case TO: fd << " to "; break; + default: ivl_assert(*this, false); break; + } + right_->write_to_stream(fd); + } +} diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 557284ad4..b722034cb 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -87,10 +87,6 @@ static ActiveScope*active_scope = new ActiveScope; static stack scope_stack; static SubprogramHeader*active_sub = NULL; -// perm_strings for attributes -const static perm_string left_attr = perm_string::literal("left"); -const static perm_string right_attr = perm_string::literal("right"); - /* * When a scope boundary starts, call the push_scope function to push * a scope context. Preload this scope context with the contents of @@ -245,8 +241,9 @@ static void touchup_interface_for_functions(std::list*ports) const VType* vtype; - prange_t* range; - std::list*range_list; + ExpRange*range; + std::list*range_list; + ExpRange::range_dir_t range_dir; ExpArithmetic::fun_t arithmetic_op; std::list*adding_terms; @@ -305,8 +302,6 @@ static void touchup_interface_for_functions(std::list*ports) /* The rules may have types. */ -%type direction - %type adding_operator %type simple_expression_terms @@ -372,6 +367,7 @@ static void touchup_interface_for_functions(std::list*ports) %type range %type range_list index_constraint +%type direction %type case_statement_alternative %type case_statement_alternative_list @@ -752,8 +748,9 @@ composite_type_definition /* unbounded_array_definition IEEE 1076-2008 P5.3.2.1 */ | K_array '(' index_subtype_definition_list ')' K_of subtype_indication - { std::list r; - r.push_back(new prange_t(NULL, NULL, true)); // NULL boundaries indicate unbounded array type + { std::list r; + // NULL boundaries indicate unbounded array type + r.push_back(new ExpRange(NULL, NULL, ExpRange::DOWNTO)); VTypeArray*tmp = new VTypeArray($6, &r); $$ = tmp; } @@ -983,8 +980,10 @@ design_units | design_unit ; - /* Indicate the direction as a flag, with "downto" being TRUE. */ -direction : K_to { $$ = false; } | K_downto { $$ = true; } ; +direction + : K_to { $$ = ExpRange::TO; } + | K_downto { $$ = ExpRange::DOWNTO; } + ; element_association : choices ARROW expression @@ -1498,7 +1497,7 @@ index_constraint | '(' error ')' { errormsg(@2, "Errors in the index constraint.\n"); yyerrok; - $$ = new list; + $$ = new list; } ; @@ -2096,18 +2095,15 @@ process_sensitivity_list range : simple_expression direction simple_expression - { prange_t* tmp = new prange_t($1, $3, $2); + { ExpRange* tmp = new ExpRange($1, $3, $2); $$ = tmp; } | name '\'' K_range { - prange_t*tmp = NULL; + ExpRange*tmp = NULL; ExpName*name = NULL; if((name = dynamic_cast($1))) { - ExpAttribute*left = new ExpAttribute(name, left_attr); - ExpAttribute*right = new ExpAttribute(name, right_attr); - tmp = new prange_t(left, right, true); - tmp->set_auto_dir(); + tmp = new ExpRange(name, false); } else { errormsg(@1, "'range attribute can be used with named expressions only"); } @@ -2115,13 +2111,10 @@ range } | name '\'' K_reverse_range { - prange_t*tmp = NULL; + ExpRange*tmp = NULL; ExpName*name = NULL; if((name = dynamic_cast($1))) { - ExpAttribute*left = new ExpAttribute(name, left_attr); - ExpAttribute*right = new ExpAttribute(name, right_attr); - tmp = new prange_t(left, right, false); - tmp->set_auto_dir(); + tmp = new ExpRange(name, true); } else { errormsg(@1, "'reverse_range attribute can be used with named expressions only"); } @@ -2131,12 +2124,12 @@ range range_list : range - { list*tmp = new list; + { list*tmp = new list; tmp->push_back($1); $$ = tmp; } | range_list ',' range - { list*tmp = $1; + { list*tmp = $1; tmp->push_back($3); $$ = tmp; } diff --git a/vhdlpp/parse_misc.cc b/vhdlpp/parse_misc.cc index 752f7eeb9..cc9de0a1e 100644 --- a/vhdlpp/parse_misc.cc +++ b/vhdlpp/parse_misc.cc @@ -113,14 +113,14 @@ static const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_n } const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name, - ScopeBase*scope, list*ranges) + ScopeBase*scope, list*ranges) { if (ranges->size() == 1) { - prange_t*tmpr = ranges->front(); - Expression*lef = tmpr->expr_left(); - Expression*rig = tmpr->expr_right(); + ExpRange*tmpr = ranges->front(); + Expression*lef = tmpr->left(); + Expression*rig = tmpr->right(); return calculate_subtype_array(loc, base_name, scope, - lef, tmpr->is_downto(), rig); + lef, tmpr->direction(), rig); } sorrymsg(loc, "Don't know how to handle multiple ranges here.\n"); @@ -130,7 +130,7 @@ const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name, const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name, ScopeBase*scope, Expression*range_left, - bool downto, + int direction, Expression*range_right) { const VType*base_type = parse_type_by_name(lex_strings.make(base_name)); @@ -148,7 +148,7 @@ const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name, if(range_left->evaluate(scope, left_val) && range_right->evaluate(scope, right_val)) { subtype = new VTypeRangeConst(base_type, left_val, right_val); } else { - subtype = new VTypeRangeExpr(base_type, range_left, range_right, downto); + subtype = new VTypeRangeExpr(base_type, range_left, range_right, direction); } return subtype; diff --git a/vhdlpp/parse_misc.h b/vhdlpp/parse_misc.h index a18335245..195264298 100644 --- a/vhdlpp/parse_misc.h +++ b/vhdlpp/parse_misc.h @@ -26,7 +26,7 @@ class ActiveScope; class Architecture; class Expression; class Package; -class prange_t; +class ExpRange; class ScopeBase; class VType; @@ -35,11 +35,11 @@ extern void bind_architecture_to_entity(const char*ename, Architecture*arch); extern const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name, ScopeBase*scope, - std::list*ranges); + std::list*ranges); extern const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name, ScopeBase*scope, Expression*range_left, - bool downto, + int direction, Expression*range_right); /* diff --git a/vhdlpp/parse_types.h b/vhdlpp/parse_types.h index 403057831..65dd3a994 100644 --- a/vhdlpp/parse_types.h +++ b/vhdlpp/parse_types.h @@ -68,35 +68,6 @@ class instant_list_t { std::list* labels_; }; -class prange_t { - public: - prange_t(Expression* left, Expression* right, bool dir) - : left_(left), right_(right), direction_(dir), auto_dir_(false) {} - prange_t(const prange_t&other) : - left_(other.left_->clone()), right_(other.right_->clone()), - direction_(other.direction_), auto_dir_(other.auto_dir_) {} - ~prange_t() { delete left_; delete right_; } - void dump(ostream&out, int indent) const; - - inline Expression*msb() { return direction_? left_ : right_; } - inline Expression*lsb() { return direction_? right_: left_; } - - inline bool is_downto() const { return direction_; } - inline void set_auto_dir(bool enabled = true) { auto_dir_ = enabled; }; - inline bool is_auto_dir() const { return auto_dir_; } - - inline Expression*expr_left() { return left_; } - inline Expression*expr_right() { return right_; } - - private: - Expression *left_, *right_; - bool direction_; - bool auto_dir_; - - private: //not implemented - prange_t operator=(const prange_t&); -}; - struct adding_term { ExpArithmetic::fun_t op; Expression*term; diff --git a/vhdlpp/sequential.cc b/vhdlpp/sequential.cc index f3c1d1c4a..d0f0f914b 100644 --- a/vhdlpp/sequential.cc +++ b/vhdlpp/sequential.cc @@ -238,7 +238,7 @@ void LoopStatement::visit(SeqStmtVisitor& func) func(this); } -ForLoopStatement::ForLoopStatement(perm_string scope_name, perm_string it, prange_t* range, list* stmts) +ForLoopStatement::ForLoopStatement(perm_string scope_name, perm_string it, ExpRange* range, list* stmts) : LoopStatement(scope_name, stmts), it_(it), range_(range) { } diff --git a/vhdlpp/sequential.h b/vhdlpp/sequential.h index 2ddd00fd4..ce68bcc3e 100644 --- a/vhdlpp/sequential.h +++ b/vhdlpp/sequential.h @@ -250,7 +250,7 @@ class WhileLoopStatement : public LoopStatement { class ForLoopStatement : public LoopStatement { public: ForLoopStatement(perm_string loop_name, - perm_string index, prange_t*, list*); + perm_string index, ExpRange*, list*); ~ForLoopStatement(); int elaborate(Entity*ent, ScopeBase*scope); @@ -264,7 +264,7 @@ class ForLoopStatement : public LoopStatement { int emit_runtime_(ostream&out, Entity*ent, ScopeBase*scope); perm_string it_; - prange_t* range_; + ExpRange* range_; }; class BasicLoopStatement : public LoopStatement { diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index 2f09ad0a6..0431a1f53 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -383,10 +383,10 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, ScopeBase*scope) ivl_assert(*this, range_); int64_t start_val; - bool start_rc = range_->msb()->evaluate(ent, scope, start_val); + bool start_rc = range_->left()->evaluate(ent, scope, start_val); int64_t finish_val; - bool finish_rc = range_->lsb()->evaluate(ent, scope, finish_val); + bool finish_rc = range_->right()->evaluate(ent, scope, finish_val); perm_string scope_name = loop_name(); if (scope_name.nil()) { @@ -403,48 +403,31 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, ScopeBase*scope) // determined during the run-time errors += emit_runtime_(out, ent, scope); } else { - bool dir = range_->is_downto(); + ExpRange::range_dir_t dir = range_->direction(); - if (!dir) { - int64_t tmp = start_val; - start_val = finish_val; - finish_val = tmp; - } + if(dir == ExpRange::AUTO) + dir = start_val < finish_val ? ExpRange::TO : ExpRange::DOWNTO; - if (dir && (start_val < finish_val)) { - if(range_->is_auto_dir()) { - dir = false; - } else { - out << "begin /* Degenerate loop at " << get_fileline() - << ": " << start_val - << " downto " << finish_val << " */ end" << endl - << "end" << endl; - return errors; - } - } - - else if (!dir && start_val > finish_val) { - if(range_->is_auto_dir()) { - dir = true; - } else { - out << "begin /* Degenerate loop at " << get_fileline() - << ": " << start_val - << " to " << finish_val << " */ end" << endl - << "end" << endl; - return errors; - } + if ((dir == ExpRange::DOWNTO && start_val < finish_val) || + (dir == ExpRange::TO && start_val > finish_val)) { + out << "begin /* Degenerate loop at " << get_fileline() + << ": " << start_val; + out << (dir == ExpRange::DOWNTO ? " downto " : " to "); + out << finish_val << " */ end" << endl + << "end" << endl; + return errors; } out << "for (\\" << it_ << " = " << start_val << " ; "; - if (dir) + if (dir == ExpRange::DOWNTO) out << "\\" << it_ << " >= " << finish_val; else out << "\\" << it_ << " <= " << finish_val; out << "; \\" << it_ << " = \\" << it_; - if (dir) + if (dir == ExpRange::DOWNTO) out << " - 1)"; else out << " + 1)"; @@ -463,9 +446,7 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, ScopeBase*scope) void ForLoopStatement::write_to_stream(ostream&fd) { fd << "for " << it_ << " in "; - range_->expr_left()->write_to_stream(fd); - fd << " to "; - range_->expr_right()->write_to_stream(fd); + range_->write_to_stream(fd); fd << " loop" << endl; write_to_stream_substatements(fd); fd << "end loop;" << endl; @@ -476,21 +457,21 @@ int ForLoopStatement::emit_runtime_(ostream&out, Entity*ent, ScopeBase*scope) int errors = 0; out << "for (\\" << it_ << " = "; - errors += range_->expr_left()->emit(out, ent, scope); + errors += range_->left()->emit(out, ent, scope); // Twisted way of determining the loop direction at runtime out << " ;\n("; - errors += range_->expr_left()->emit(out, ent, scope); + errors += range_->left()->emit(out, ent, scope); out << " < "; - errors += range_->expr_right()->emit(out, ent, scope); + errors += range_->right()->emit(out, ent, scope); out << " ? \\" << it_ << " <= "; - errors += range_->expr_right()->emit(out, ent, scope); + errors += range_->right()->emit(out, ent, scope); out << " : \\" << it_ << " >= "; - errors += range_->expr_right()->emit(out, ent, scope); + errors += range_->right()->emit(out, ent, scope); out << ");\n\\" << it_ << " = \\" << it_ << " + ("; - errors += range_->expr_left()->emit(out, ent, scope); + errors += range_->left()->emit(out, ent, scope); out << " < "; - errors += range_->expr_right()->emit(out, ent, scope); + errors += range_->right()->emit(out, ent, scope); out << " ? 1 : -1))"; return errors; diff --git a/vhdlpp/vtype.cc b/vhdlpp/vtype.cc index 6bf8c4eb2..64e94ef46 100644 --- a/vhdlpp/vtype.cc +++ b/vhdlpp/vtype.cc @@ -108,21 +108,18 @@ VTypeArray::VTypeArray(const VType*element, const vector&r, /* * Create a VTypeArray range set from a list of parsed ranges. - * FIXME: We are copying pointers from the prange_t object into the - * range_t. This means that we cannot delete the prange_t object + * FIXME: We are copying pointers from the ExpRange object into the + * range_t. This means that we cannot delete the ExpRange object * unless we invent a way to remove the pointers from that object. So * this is a memory leak. Something to fix. */ -VTypeArray::VTypeArray(const VType*element, std::list*r, bool sv) +VTypeArray::VTypeArray(const VType*element, std::list*r, bool sv) : etype_(element), ranges_(r->size()), signed_flag_(sv), parent_(NULL) { for (size_t idx = 0 ; idx < ranges_.size() ; idx += 1) { - prange_t*curp = r->front(); + ExpRange*curp = r->front(); r->pop_front(); - Expression*msb = curp->msb(); - Expression*lsb = curp->lsb(); - bool dir = curp->is_downto(); - ranges_[idx] = range_t(msb, lsb, dir); + ranges_[idx] = range_t(curp->msb(), curp->lsb(), curp->direction()); } } diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index d97d13a9a..cc310ad90 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -33,7 +33,7 @@ class Architecture; class ScopeBase; class Entity; class Expression; -class prange_t; +class ExpRange; class VTypeDef; class ScopeBase; @@ -210,7 +210,7 @@ class VTypeArray : public VType { public: VTypeArray(const VType*etype, const std::vector&r, bool signed_vector = false); - VTypeArray(const VType*etype, std::list*r, bool signed_vector = false); + VTypeArray(const VType*etype, std::list*r, bool signed_vector = false); VTypeArray(const VType*etype, int msb, int lsb, bool signed_vector = false); ~VTypeArray(); From 71c63bf99391872b6a5556e07cc242d5759c7843 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 5 Jan 2016 10:29:07 +0100 Subject: [PATCH 16/25] vhdlpp: Added argument_list token. --- vhdlpp/parse.y | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index b722034cb..52f7bf05f 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -336,7 +336,7 @@ static void touchup_interface_for_functions(std::list*ports) %type variable_declaration_assign_opt waveform_element interface_element_expression %type waveform waveform_elements -%type name_list expression_list +%type name_list expression_list argument_list argument_list_opt %type process_sensitivity_list process_sensitivity_list_opt %type selected_names use_clause @@ -444,6 +444,13 @@ architecture_statement_part } ; +argument_list : '(' expression_list ')' { $$ = $2; }; + +argument_list_opt + : argument_list { $$ = $1; } + | { $$ = 0; } + ; + assertion_statement : K_assert expression report_statement { ReportStmt*report = dynamic_cast($3); @@ -1678,14 +1685,14 @@ name /* IEEE 1076-2008 P8.1 */ function calls. The only way we can tell the difference is from left context, namely whether the name is a type name or function name. If none of the above, treat it as a array element select. */ - | IDENTIFIER '(' expression_list ')' + | IDENTIFIER argument_list { perm_string name = lex_strings.make($1); delete[]$1; if (active_scope->is_vector_name(name) || is_subprogram_param(name)) { - ExpName*tmp = new ExpName(name, $3); + ExpName*tmp = new ExpName(name, $2); $$ = tmp; } else { - ExpFunc*tmp = new ExpFunc(name, $3); + ExpFunc*tmp = new ExpFunc(name, $2); $$ = tmp; } FILE_NAME($$, @1); @@ -1979,11 +1986,11 @@ procedure_call delete[] $1; $$ = tmp; } - | IDENTIFIER '(' expression_list ')' ';' + | IDENTIFIER argument_list ';' { - ProcedureCall* tmp = new ProcedureCall(lex_strings.make($1), $3); + ProcedureCall* tmp = new ProcedureCall(lex_strings.make($1), $2); delete[] $1; - delete $3; // parameters are copied in this variant + delete $2; // parameters are copied in this variant $$ = tmp; } | IDENTIFIER '(' error ')' ';' From dff1ad08b0a31858596e701ac83ee0b6dc316cc5 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 5 Jan 2016 13:35:39 +0100 Subject: [PATCH 17/25] vhdlpp: ExpAttribute split to Exp{Obj,Type}Attribute. --- vhdlpp/architec_elaborate.cc | 2 +- vhdlpp/debug.cc | 11 +++- vhdlpp/expression.cc | 83 +++++++++++++++++++++++++---- vhdlpp/expression.h | 70 +++++++++++++++++++------ vhdlpp/expression_elaborate.cc | 27 ++++++---- vhdlpp/expression_emit.cc | 14 ++++- vhdlpp/expression_evaluate.cc | 95 +++++++++++++++++++--------------- vhdlpp/expression_stream.cc | 8 ++- vhdlpp/parse.y | 16 ++++-- 9 files changed, 239 insertions(+), 87 deletions(-) diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index 645028af0..cfedeb467 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -228,7 +228,7 @@ int ProcessStatement::rewrite_as_always_edge_(Entity*, Architecture*) } // If operand1 is not an 'event attribute, I give up. - const ExpAttribute*op1 = dynamic_cast(op1_raw); + const ExpObjAttribute*op1 = dynamic_cast(op1_raw); if (op1 == 0) return -1; if (op1->peek_attribute() != "event") diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index f3dbc4b55..6f044b2e8 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -251,9 +251,16 @@ void ExpAggregate::choice_t::dump(ostream&out, int indent) const out << setw(indent) << "" << "?choice_t?" << endl; } -void ExpAttribute::dump(ostream&out, int indent) const +void ExpTypeAttribute::dump(ostream&out, int indent) const { - out << setw(indent) << "" << "Attribute " << name_ + out << setw(indent) << "" << "Attribute (type-related) " << name_ + << " at " << get_fileline() << endl; + base_->show(out); +} + +void ExpObjAttribute::dump(ostream&out, int indent) const +{ + out << setw(indent) << "" << "Attribute (object-related) " << name_ << " at " << get_fileline() << endl; base_->dump(out, indent+4); } diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index 72d4c4435..6e7bb885b 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -54,29 +54,88 @@ bool Expression::symbolic_compare(const Expression*) const return false; } -ExpAttribute::ExpAttribute(ExpName*bas, perm_string nam) -: base_(bas), name_(nam) +ExpAttribute::ExpAttribute(perm_string nam, list*args) +: name_(nam), args_(args) { } ExpAttribute::~ExpAttribute() { - /* Different attributes can point to the same base so we cannot delete this here. - * Look at the vhdl_range test with valgrind to see this issue. */ -// delete base_; + if(args_) { + for(list::iterator it = args_->begin(); + it != args_->end(); ++it) { + delete *it; + } + } + + delete args_; } -Expression*ExpAttribute::clone() const -{ - return new ExpAttribute(static_cast(base_->clone()), name_); +list*ExpAttribute::clone_args() const { + list*new_args = NULL; + + if(args_) { + for(list::iterator it = args_->begin(); + it != args_->end(); ++it) { + new_args->push_back((*it)->clone()); + } + } + + return new_args; } -void ExpAttribute::visit(ExprVisitor& func) +void ExpAttribute::visit_args(ExprVisitor& func) { + if(args_) { + for(list::iterator it = args_->begin(); + it != args_->end(); ++it) { + func(*it); + } + } +} + +ExpObjAttribute::ExpObjAttribute(ExpName*base, perm_string name, list*args) +: ExpAttribute(name, args), base_(base) +{ +} + +ExpObjAttribute::~ExpObjAttribute() +{ +} + +Expression*ExpObjAttribute::clone() const +{ + return new ExpObjAttribute(static_cast(base_->clone()), + name_, clone_args()); +} + +void ExpObjAttribute::visit(ExprVisitor& func) +{ + visit_args(func); base_->visit(func); func(this); } +ExpTypeAttribute::ExpTypeAttribute(const VType*base, perm_string name, list*args) +: ExpAttribute(name, args), base_(base) +{ +} + +ExpTypeAttribute::~ExpTypeAttribute() +{ +} + +Expression*ExpTypeAttribute::clone() const +{ + return new ExpTypeAttribute(base_, name_, clone_args()); +} + +void ExpTypeAttribute::visit(ExprVisitor& func) +{ + visit_args(func); + func(this); +} + const perm_string ExpAttribute::LEFT = perm_string::literal("left"); const perm_string ExpAttribute::RIGHT = perm_string::literal("right"); @@ -772,7 +831,8 @@ Expression* ExpRange::lsb() Expression*ExpRange::left() { if(range_expr_ && !left_) - left_ = new ExpAttribute(range_base_, ExpAttribute::LEFT); + // TODO check if it is an object or type + left_ = new ExpObjAttribute(range_base_, ExpAttribute::LEFT, NULL); return left_; } @@ -780,7 +840,8 @@ Expression*ExpRange::left() Expression*ExpRange::right() { if(range_expr_ && !right_) - right_ = new ExpAttribute(range_base_, ExpAttribute::RIGHT); + // TODO check if it is an object or type + right_ = new ExpObjAttribute(range_base_, ExpAttribute::RIGHT, NULL); return right_; } diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index e9513b31e..eb93b5fe2 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -124,7 +124,7 @@ class Expression : public LineInfo { virtual void dump(ostream&out, int indent = 0) const =0; virtual ostream& dump_inline(ostream&out) const; - // Recursively visits a tree of expressions (useful of complex expressions). + // Recursively visits a tree of expressions (useful for complex expressions). virtual void visit(ExprVisitor& func) { func(this); } protected: @@ -355,30 +355,68 @@ class ExpArithmetic : public ExpBinary { class ExpAttribute : public Expression { public: - ExpAttribute(ExpName*base, perm_string name); - ~ExpAttribute(); - - Expression*clone() const; + ExpAttribute(perm_string name,std::list*args); + virtual ~ExpAttribute(); inline perm_string peek_attribute() const { return name_; } - inline const ExpName* peek_base() const { return base_; } - - const VType*probe_type(Entity*ent, ScopeBase*scope) const; - int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); - void write_to_stream(std::ostream&fd) const; - int emit(ostream&out, Entity*ent, ScopeBase*scope); - // Some attributes can be evaluated at compile time - bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; - void dump(ostream&out, int indent = 0) const; - void visit(ExprVisitor& func); // Constants for the standard attributes static const perm_string LEFT; static const perm_string RIGHT; + protected: + std::list*clone_args() const; + void visit_args(ExprVisitor& func); + bool evaluate_type_attr(const VType*type, Entity*ent, ScopeBase*scope, int64_t&val) const; + bool test_array_type(const VType*type) const; + + perm_string name_; + std::list*args_; +}; + +class ExpObjAttribute : public ExpAttribute { + public: + ExpObjAttribute(ExpName*base, perm_string name, std::list*args); + ~ExpObjAttribute(); + + Expression*clone() const; + + inline const ExpName* peek_base() const { return base_; } + + int emit(ostream&out, Entity*ent, ScopeBase*scope); + const VType*probe_type(Entity*ent, ScopeBase*scope) const; + int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); + void write_to_stream(std::ostream&fd) const; + // Some attributes can be evaluated at compile time + bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; + void dump(ostream&out, int indent = 0) const; + void visit(ExprVisitor& func); + private: ExpName*base_; - perm_string name_; +}; + +class ExpTypeAttribute : public ExpAttribute { + public: + ExpTypeAttribute(const VType*base, perm_string name, std::list*args); + ~ExpTypeAttribute(); + + Expression*clone() const; + + inline const VType* peek_base() const { return base_; } + + int emit(ostream&out, Entity*ent, ScopeBase*scope); + const VType*probe_type(Entity*ent, ScopeBase*scope) const; + int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); + void write_to_stream(std::ostream&fd) const; + // Some attributes can be evaluated at compile time + bool evaluate(ScopeBase*scope, int64_t&val) const; + bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; + void dump(ostream&out, int indent = 0) const; + void visit(ExprVisitor& func); + + private: + const VType*base_; }; class ExpBitstring : public Expression { diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 0ca07f0d7..f0758c631 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -327,7 +327,8 @@ int ExpName::elaborate_rval(Entity*ent, ScopeBase*scope, const InterfacePort*lva int Expression::elaborate_expr(Entity*, ScopeBase*, const VType*) { - cerr << get_fileline() << ": internal error: I don't know how to elaborate expression type=" << typeid(*this).name() << endl; + cerr << get_fileline() << ": internal error: I don't know how to " + << "elaborate expression type=" << typeid(*this).name() << endl; return 1; } @@ -582,23 +583,29 @@ const VType* ExpArithmetic::resolve_operand_types_(const VType*t1, const VType*t return 0; } -const VType* ExpAttribute::probe_type(Entity*ent, ScopeBase*scope) const +int ExpObjAttribute::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) { - base_->probe_type(ent, scope); + const VType*sub_type = base_->probe_type(ent, scope); + return base_->elaborate_expr(ent, scope, sub_type); +} - if (name_ == "length" || name_ == "left" || name_ == "right") { +const VType* ExpObjAttribute::probe_type(Entity*, ScopeBase*) const +{ + if (name_ == "length" || name_ == "left" || name_ == "right") return &primitive_NATURAL; - } + return NULL; +} + +int ExpTypeAttribute::elaborate_expr(Entity*, ScopeBase*, const VType*) +{ + // This is just to mute warnings, there is nothing to elaborate here return 0; } -int ExpAttribute::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) +const VType* ExpTypeAttribute::probe_type(Entity*, ScopeBase*) const { - int errors = 0; - const VType*sub_type = base_->probe_type(ent, scope); - errors += base_->elaborate_expr(ent, scope, sub_type); - return errors; + return NULL; } const VType*ExpBitstring::fit_type(Entity*, ScopeBase*, const VTypeArray*atype) const diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 223f4e9ea..97e0d5b48 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -331,7 +331,7 @@ int ExpAggregate::emit_record_(ostream&out, Entity*ent, ScopeBase*scope, const V return errors; } -int ExpAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope) +int ExpObjAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; @@ -365,12 +365,24 @@ int ExpAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope) return errors; } + // Fallback out << "$ivl_attribute("; errors += base_->emit(out, ent, scope); out << ", \"" << name_ << "\")"; return errors; } +int ExpTypeAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope) +{ + int errors = 0; + + // Fallback + out << "$ivl_attribute("; + errors += base_->emit_def(out, empty_perm_string); + out << ", \"" << name_ << "\")"; + return errors; +} + int ExpArithmetic::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; diff --git a/vhdlpp/expression_evaluate.cc b/vhdlpp/expression_evaluate.cc index b88e40032..577defb8b 100644 --- a/vhdlpp/expression_evaluate.cc +++ b/vhdlpp/expression_evaluate.cc @@ -73,56 +73,69 @@ bool ExpArithmetic::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const return true; } -bool ExpAttribute::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const +bool ExpAttribute::test_array_type(const VType*type) const +{ + const VTypeArray*arr = dynamic_cast(type); + + if (arr == 0) { + cerr << endl << get_fileline() << ": error: " + << "Cannot apply the '" << name_ << " attribute to non-array objects" + << endl; + ivl_assert(*this, false); + return false; + } + + if (arr->dimensions() > 1) { + cerr << endl << get_fileline() << ": error: " + << "Cannot apply the '" << name_ + << " attribute to multidimensional arrays" << endl; + return false; + } + + if (arr->dimension(0).is_box()) + return false; + + return true; +} + +bool ExpAttribute::evaluate_type_attr(const VType*type, Entity*ent, ScopeBase*scope, int64_t&val) const +{ + if (name_ == "length" && test_array_type(type)) { + int64_t size = type->get_width(scope); + + if(size > 0) { + val = size; + return true; + } + } else if (name_ == "left" && test_array_type(type)) { + const VTypeArray*arr = dynamic_cast(type); + return arr->dimension(0).msb()->evaluate(ent, scope, val); + } else if (name_ == "right" && test_array_type(type)) { + const VTypeArray*arr = dynamic_cast(type); + return arr->dimension(0).lsb()->evaluate(ent, scope, val); + } + + return false; +} + +bool ExpObjAttribute::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const { const VType*base_type = base_->peek_type(); if (base_type == NULL) - base_type = base_->probe_type(ent, scope); + base_type = base_->probe_type(ent, scope); - if (base_type == NULL) - return false; - - if (name_ == "left" || name_ == "right") { - const VTypeArray*arr = dynamic_cast(base_type); - if (arr == NULL) { - cerr << endl << get_fileline() << ": error: " - << "Cannot apply the '" << name_ - << " attribute to non-array objects" << endl; - return false; - } - - if (arr->dimensions() != 1) { - cerr << endl << get_fileline() << ": error: " - << "Cannot apply the '" << name_ - << " attribute to multidimensional arrays" << endl; - return false; - } - - if (arr->dimension(0).is_box()) - return false; - - if (name_ == "left") { - return arr->dimension(0).msb()->evaluate(ent, scope, val); - } else if (name_ == "right") { - return arr->dimension(0).lsb()->evaluate(ent, scope, val); - } else { - ivl_assert(*this, false); - } - } - - else if (name_ == "length") { - int64_t size = base_type->get_width(scope); - - if (size > 0) { - val = size; - return true; - } - } + if (base_type) + return evaluate_type_attr(base_type, ent, scope, val); return false; } +bool ExpTypeAttribute::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const +{ + return evaluate_type_attr(base_, ent, scope, val); +} + bool ExpName::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const { if (prefix_.get()) { diff --git a/vhdlpp/expression_stream.cc b/vhdlpp/expression_stream.cc index 059ba80de..b62225dd3 100644 --- a/vhdlpp/expression_stream.cc +++ b/vhdlpp/expression_stream.cc @@ -107,7 +107,13 @@ void ExpArithmetic::write_to_stream(ostream&out) const out << ")"; } -void ExpAttribute::write_to_stream(ostream&fd) const +void ExpObjAttribute::write_to_stream(ostream&fd) const +{ + base_->write_to_stream(fd); + fd << "'" << name_; +} + +void ExpTypeAttribute::write_to_stream(ostream&fd) const { base_->write_to_stream(fd); fd << "'" << name_; diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 52f7bf05f..217a06dad 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -1882,10 +1882,18 @@ prefix /* IEEE 1076-2008 P8.1 */ primary : name { $$ = $1; } - | name '\'' IDENTIFIER - { perm_string name = lex_strings.make($3); - ExpName*base = dynamic_cast ($1); - ExpAttribute*tmp = new ExpAttribute(base, name); + | name '\'' IDENTIFIER argument_list_opt + { ExpAttribute*tmp = NULL; + perm_string attr = lex_strings.make($3); + ExpName*base = dynamic_cast($1); + const VType*type = parse_type_by_name(base->peek_name()); + + if(type) { + tmp = new ExpTypeAttribute(type, attr, $4); + } else { + tmp = new ExpObjAttribute(base, attr, $4); + } + FILE_NAME(tmp, @3); delete[]$3; $$ = tmp; From b711f16f055c67b2627e2bc4a0e03d774018a54c Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 5 Jan 2016 13:54:05 +0100 Subject: [PATCH 18/25] vhdlpp: 'image attribute. --- vhdlpp/expression_elaborate.cc | 3 +++ vhdlpp/expression_emit.cc | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index f0758c631..a84bfbdd9 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -605,6 +605,9 @@ int ExpTypeAttribute::elaborate_expr(Entity*, ScopeBase*, const VType*) const VType* ExpTypeAttribute::probe_type(Entity*, ScopeBase*) const { + if(name_ == "image") + return &primitive_STRING; + return NULL; } diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 97e0d5b48..53ccde727 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -376,6 +376,30 @@ int ExpTypeAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; + // Special case: The image attribute + if (name_=="image") { + if(!args_ || args_->size() != 1) { + out << "/* Invalid 'image attribute */" << endl; + cerr << get_fileline() << ": error: 'image attribute takes " + << "exactly one argument." << endl; + ++errors; + } else { + out << "$sformatf(\""; + + if(base_->type_match(&primitive_INTEGER)) + out << "%0d"; + else if(base_->type_match(&primitive_REAL)) + out << "%f"; + else if(base_->type_match(&primitive_CHARACTER)) + out << "'%c'"; + + out << "\","; + args_->front()->emit(out, ent, scope); + out << ")"; + } + return errors; + } + // Fallback out << "$ivl_attribute("; errors += base_->emit_def(out, empty_perm_string); From 214c940a1a80dc86d8dd7c50fddca748c2490399 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 6 Jan 2016 09:38:34 +0100 Subject: [PATCH 19/25] vhdlpp: Fixing memory leaks and muting valgrind. --- vhdlpp/expression.cc | 18 +++++++++--------- vhdlpp/expression.h | 2 +- vhdlpp/parse.y | 6 ++++-- vhdlpp/parse_types.h | 3 ++- vhdlpp/scope.cc | 1 + vhdlpp/sequential.cc | 4 +++- vhdlpp/std_types.cc | 22 ++++++++++++---------- 7 files changed, 32 insertions(+), 24 deletions(-) diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index 6e7bb885b..49e19242e 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -101,6 +101,7 @@ ExpObjAttribute::ExpObjAttribute(ExpName*base, perm_string name, list(range_base_->clone()), + ExpAttribute::LEFT, NULL); return left_; } @@ -841,7 +841,7 @@ Expression*ExpRange::right() { if(range_expr_ && !right_) // TODO check if it is an object or type - right_ = new ExpObjAttribute(range_base_, ExpAttribute::RIGHT, NULL); - + right_ = new ExpObjAttribute(static_cast(range_base_->clone()), + ExpAttribute::RIGHT, NULL); return right_; } diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index eb93b5fe2..7ad596e23 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -399,7 +399,7 @@ class ExpObjAttribute : public ExpAttribute { class ExpTypeAttribute : public ExpAttribute { public: ExpTypeAttribute(const VType*base, perm_string name, std::list*args); - ~ExpTypeAttribute(); + // no destructor - VType objects (base_) are shared between many expressions Expression*clone() const; diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 217a06dad..dbc561867 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -1264,8 +1264,8 @@ file_declaration // add file_open() call in 'initial' block params.push_back(new ExpName(*cur)); - params.push_back($5->filename()); - params.push_back($5->kind()); + params.push_back($5->filename()->clone()); + params.push_back($5->kind()->clone()); ProcedureCall*fopen_call = new ProcedureCall(perm_string::literal("file_open"), ¶ms); active_scope->add_initializer(fopen_call); @@ -1274,6 +1274,8 @@ file_declaration params.push_back(new ExpName(*cur)); ProcedureCall*fclose_call = new ProcedureCall(perm_string::literal("file_close"), ¶ms); active_scope->add_finalizer(fclose_call); + + delete $5; } } diff --git a/vhdlpp/parse_types.h b/vhdlpp/parse_types.h index 65dd3a994..711d45a0b 100644 --- a/vhdlpp/parse_types.h +++ b/vhdlpp/parse_types.h @@ -26,7 +26,8 @@ class named_expr_t { public: - named_expr_t (perm_string n, Expression*e) : name_(n), expr_(e) { } + named_expr_t(perm_string n, Expression*e) : name_(n), expr_(e) { } + ~named_expr_t() { delete expr_; } perm_string name() const { return name_; } Expression* expr() const { return expr_; } diff --git a/vhdlpp/scope.cc b/vhdlpp/scope.cc index bc1e42979..5084986a3 100644 --- a/vhdlpp/scope.cc +++ b/vhdlpp/scope.cc @@ -90,6 +90,7 @@ void ScopeBase::cleanup() * objects from the other scopes untouched. */ delete_all(new_signals_); + delete_all(new_variables_); delete_all(new_components_); delete_all(cur_types_); delete_all(cur_constants_); diff --git a/vhdlpp/sequential.cc b/vhdlpp/sequential.cc index d0f0f914b..3e572fce0 100644 --- a/vhdlpp/sequential.cc +++ b/vhdlpp/sequential.cc @@ -185,7 +185,7 @@ ProcedureCall::ProcedureCall(perm_string name, std::list* param_lis for(std::list::const_iterator it = param_list->begin(); it != param_list->end(); ++it) { - param_list_->push_back(new named_expr_t(empty_perm_string, (*it)->clone())); + param_list_->push_back(new named_expr_t(empty_perm_string, *it)); } } @@ -199,6 +199,8 @@ ProcedureCall::~ProcedureCall() param_list_->pop_front(); delete cur; } + + delete param_list_; } ReturnStmt::ReturnStmt(Expression*val) diff --git a/vhdlpp/std_types.cc b/vhdlpp/std_types.cc index 516b6ac17..9bb9744dd 100644 --- a/vhdlpp/std_types.cc +++ b/vhdlpp/std_types.cc @@ -46,20 +46,20 @@ const VTypeArray primitive_UNSIGNED(&primitive_STDLOGIC, vector*enum_BOOLEAN_vals = new list; - enum_BOOLEAN_vals->push_back(perm_string::literal("false")); - enum_BOOLEAN_vals->push_back(perm_string::literal("true")); - VTypeEnum*enum_BOOLEAN = new VTypeEnum(enum_BOOLEAN_vals); + list enum_BOOLEAN_vals; + enum_BOOLEAN_vals.push_back(perm_string::literal("false")); + enum_BOOLEAN_vals.push_back(perm_string::literal("true")); + VTypeEnum*enum_BOOLEAN = new VTypeEnum(&enum_BOOLEAN_vals); type_BOOLEAN.set_definition(enum_BOOLEAN); std_types[type_BOOLEAN.peek_name()] = &type_BOOLEAN; std_enums.push_back(enum_BOOLEAN); // file_open_kind - list*enum_FILE_OPEN_KIND_vals = new list; - enum_FILE_OPEN_KIND_vals->push_back(perm_string::literal("read_mode")); - enum_FILE_OPEN_KIND_vals->push_back(perm_string::literal("write_mode")); - enum_FILE_OPEN_KIND_vals->push_back(perm_string::literal("append_mode")); - VTypeEnum*enum_FILE_OPEN_KIND = new VTypeEnum(enum_FILE_OPEN_KIND_vals); + list enum_FILE_OPEN_KIND_vals; + enum_FILE_OPEN_KIND_vals.push_back(perm_string::literal("read_mode")); + enum_FILE_OPEN_KIND_vals.push_back(perm_string::literal("write_mode")); + enum_FILE_OPEN_KIND_vals.push_back(perm_string::literal("append_mode")); + VTypeEnum*enum_FILE_OPEN_KIND = new VTypeEnum(&enum_FILE_OPEN_KIND_vals); type_FILE_OPEN_KIND.set_definition(enum_FILE_OPEN_KIND); std_types[type_FILE_OPEN_KIND.peek_name()] = &type_FILE_OPEN_KIND; std_enums.push_back(enum_FILE_OPEN_KIND); @@ -80,10 +80,12 @@ void delete_global_types() { typedef_context_t typedef_ctx; for(map::iterator cur = std_types.begin(); - cur != std_types.end() ; ++ cur) { + cur != std_types.end(); ++cur) { delete cur->second->peek_definition(); delete cur->second; } + + // std_enums are destroyed above } const VTypeEnum*find_std_enum_name(perm_string name) From ba274936e5a82d50858333de2023a3c41b47baea Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 6 Jan 2016 14:08:31 +0100 Subject: [PATCH 20/25] vhdlpp: Added 'image attribute for time type. --- vhdlpp/expression_emit.cc | 2 ++ vpi/sys_display.c | 27 +++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 53ccde727..8a22c5500 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -392,6 +392,8 @@ int ExpTypeAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope) out << "%f"; else if(base_->type_match(&primitive_CHARACTER)) out << "'%c'"; + else if(base_->type_match(&primitive_TIME)) + out << "%+0t"; out << "\","; args_->front()->emit(out, ent, scope); diff --git a/vpi/sys_display.c b/vpi/sys_display.c index c65c1b14d..28031a73f 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -621,10 +621,6 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, case 't': case 'T': *idx += 1; - if (plus != 0) { - vpi_printf("WARNING: %s:%d: invalid format %s%s.\n", - info->filename, info->lineno, info->name, fmtb); - } if (*idx >= info->nitems) { vpi_printf("WARNING: %s:%d: missing argument for %s%s.\n", info->filename, info->lineno, info->name, fmtb); @@ -648,6 +644,29 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, } else { char *tbuf; PLI_INT32 time_units = vpi_get(vpiTimeUnit, info->scope); + + if (plus != 0) { + /* Icarus-specific extension to print out time units. + * It is needed by vhdlpp to correctly implement time'image(). */ + PLI_INT32 time_prec = vpi_get(vpiTimePrecision, info->scope); + + if(time_units < -12) + timeformat_info.suff = strdup(" fs"); + else if(time_units < -9) + timeformat_info.suff = strdup(" ps"); + else if(time_units < -6) + timeformat_info.suff = strdup(" ns"); + else if(time_units < -3) + timeformat_info.suff = strdup(" us"); + else if(time_units < 0) + timeformat_info.suff = strdup(" ms"); + else + timeformat_info.suff = strdup(" s"); + + /* Adjust shift for get_time(), so the number indeed matches the unit */ + time_units += (3 + (time_units % 3)) % 3 + (time_prec - time_units); + } + unsigned swidth, free_flag = 0; unsigned suff_len = strlen(timeformat_info.suff); char *cp; From 32fab21e95e1f33deac1b720cd91214b8fa31eb2 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 7 Jan 2016 11:11:04 +0100 Subject: [PATCH 21/25] ivl: Allow concatenating strings returned by function calls. --- elab_expr.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elab_expr.cc b/elab_expr.cc index cb0be36ca..d4394c1cc 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -2838,7 +2838,7 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope, concat->set(idx, parms[off+idx]); } - if (wid_sum == 0) { + if (wid_sum == 0 && expr_type_ != IVL_VT_STRING) { cerr << get_fileline() << ": error: Concatenation/replication " << "may not have zero width in this context." << endl; des->errors += 1; From eb2a9be0c9a9762bbb0a59b33453d58aed885275 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Thu, 7 Jan 2016 19:11:42 +0000 Subject: [PATCH 22/25] Fix for br999 - incorrect result from binary comparison. When a binary (in)equality comparison has a constant left operand, the tgt-vvp code generator swaps the left and right operands to allow the cmpi instruction to be used. The code for swapping the operands was incorrect. --- tgt-vvp/eval_condit.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tgt-vvp/eval_condit.c b/tgt-vvp/eval_condit.c index 59c7a88c6..2e46894ef 100644 --- a/tgt-vvp/eval_condit.c +++ b/tgt-vvp/eval_condit.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2014-2016 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 @@ -76,8 +76,8 @@ static int draw_condition_binary_compare(ivl_expr_t expr) %cmp instruction. */ if (ivl_expr_width(le)==use_wid && test_immediate_vec4_ok(le)) { ivl_expr_t tmp = le; - re = le; - le = tmp; + le = re; + re = tmp; } draw_eval_vec4(le); From fbeee1bae381a9539d9e904b4a870916c09b270d Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 30 Jan 2016 17:01:13 +0000 Subject: [PATCH 23/25] Temporary fix for br995 - assignment to memory not supported in synthesis. For now, output a "sorry" message. --- synth2.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/synth2.cc b/synth2.cc index 44f7e07f6..aa9dd6389 100644 --- a/synth2.cc +++ b/synth2.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2016 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 @@ -103,6 +103,14 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope, NetNet*rsig = rval_->synthesize(des, scope, rval_); assert(rsig); + if (lval_->word() && ! dynamic_cast(lval_->word())) { + cerr << get_fileline() << ": sorry: assignment to variable " + "location in memory is not currently supported in " + "synthesis." << endl; + des->errors += 1; + return false; + } + NetNet*lsig = lval_->sig(); if (!lsig) { cerr << get_fileline() << ": error: " From a006dee990f022fa9bc8b7b1ce926dad27fd0607 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 30 Jan 2016 20:11:58 +0000 Subject: [PATCH 24/25] Fix for br994 - assertion failure when synthesising a mux. The elaborator allows the RHS of assignment to be wider than the LHS. When using an if statement to represent a mux, this meant the mux inputs could be different widths, resulting in an assertion failure during synthesis. The fix is to prune the RHS to match the LHS for each assignment. This has the benefit of minimising the mux width. --- synth2.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/synth2.cc b/synth2.cc index aa9dd6389..24fb80a03 100644 --- a/synth2.cc +++ b/synth2.cc @@ -226,6 +226,8 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope, rsig = tmp; } + rsig = crop_to_width(des, rsig, lsig->vector_width()); + if (nex_out.pin_count() > 1) { NexusSet tmp_set; nex_output(tmp_set); From 83a82914e0a11776476891ed2f5fd6f1d543efb4 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 30 Jan 2016 22:38:08 +0000 Subject: [PATCH 25/25] Temporary fix for br993 - assertion failure in flip-flop synthesis. Synthesis does not currently support some commonly used styles for representing flip-flops, e.g. q <= 0; if (en) q <= 1; or if (clr) q <= 0; if (set) q <= 1; For now, output a "sorry" message. --- synth2.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/synth2.cc b/synth2.cc index 24fb80a03..3d3805891 100644 --- a/synth2.cc +++ b/synth2.cc @@ -1421,6 +1421,16 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, are used to collect the outputs from the substatement for the inputs of the FF bank. */ NetBus tmp_out (scope, tmp_set.size()); + for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) { + unsigned ptr = nex_map.find_nexus(tmp_set[idx]); + ivl_assert(*this, ptr < nex_out.pin_count()); + if (nex_out.pin(ptr).is_linked()) { + cerr << get_fileline() << ": sorry: multiple statements " + "assigning to the same flip-flop are not yet " + "supported in synthesis." << endl; + return false; + } + } /* Create a temporary ff_ce (FF clock-enable) that accounts for the subset of outputs that this