From 0569474d179106341f9533ebf05b50996bb8d428 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 26 Aug 2015 17:29:13 +0200 Subject: [PATCH 01/24] vhdlpp: Evaluate power (**) and division remainder (REM) operators. --- vhdlpp/expression_emit.cc | 21 ++++++++++++++++++--- vhdlpp/expression_evaluate.cc | 7 ++++++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 530e64d8d8..9ab2c66fac 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -375,6 +375,22 @@ int ExpArithmetic::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; + if(fun_ == REM) { + // Special case: division remainder, defined in the VHDL standard 1076-2008/9.2.7 + // there is no direct counterpart, therefore output the formula to + // compute a remainder: A rem B = A - (A/B) * B; + out << "(("; + errors += emit_operand1(out, ent, scope); + out << ")-(("; + errors += emit_operand1(out, ent, scope); + out << ")/("; + errors += emit_operand2(out, ent, scope); + out << "))*("; + errors += emit_operand2(out, ent, scope); + out << "))"; + return errors; + } + errors += emit_operand1(out, ent, scope); switch (fun_) { @@ -396,9 +412,8 @@ int ExpArithmetic::emit(ostream&out, Entity*ent, ScopeBase*scope) case POW: out << " ** "; break; - case REM: - out << " /* ?remainder? */ "; - break; + case REM: // should not happen as it is handled above, suppress warnings + ivl_assert(*this, 0); case xCONCAT: ivl_assert(*this, 0); out << " /* ?concat? */ "; diff --git a/vhdlpp/expression_evaluate.cc b/vhdlpp/expression_evaluate.cc index 2e26ba5023..7aa9218580 100644 --- a/vhdlpp/expression_evaluate.cc +++ b/vhdlpp/expression_evaluate.cc @@ -23,6 +23,7 @@ # include "architec.h" # include # include +# include bool Expression::evaluate(ScopeBase*, int64_t&) const { @@ -68,9 +69,13 @@ bool ExpArithmetic::evaluate(ScopeBase*scope, int64_t&val) const val = val1 % val2; break; case REM: + if (val2 == 0) + return false; + val = val1 - (val1 / val2) * val2; return false; case POW: - return false; + val = (int64_t) pow(val1, val2); + break; case xCONCAT: // not possible return false; } From 5b0bf08638ec2a309239b76628a4ed76f62db32c Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 27 Aug 2015 14:13:58 +0200 Subject: [PATCH 02/24] vhdlpp: Simplified a few find_* functions. --- vhdlpp/scope.cc | 41 ++++++++++++++--------------------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/vhdlpp/scope.cc b/vhdlpp/scope.cc index d0a329514b..b178547c7c 100644 --- a/vhdlpp/scope.cc +++ b/vhdlpp/scope.cc @@ -99,11 +99,10 @@ const VType*ScopeBase::find_type(perm_string by_name) if (cur == cur_types_.end()) { cur = use_types_.find(by_name); if (cur == use_types_.end()) - return 0; - else - return cur->second; - } else - return cur->second; + return NULL; // nothing found + } + + return cur->second; } bool ScopeBase::find_constant(perm_string by_name, const VType*&typ, Expression*&exp) const @@ -115,19 +114,12 @@ bool ScopeBase::find_constant(perm_string by_name, const VType*&typ, Expression* if (cur == cur_constants_.end()) { cur = use_constants_.find(by_name); if (cur == use_constants_.end()) - return false; - else { - typ = cur->second->typ; - exp = cur->second->val; - return true; - } - } else { - typ = cur->second->typ; - exp = cur->second->val; - return true; + return false; // nothing found } - return false; + typ = cur->second->typ; + exp = cur->second->val; + return true; } Signal* ScopeBase::find_signal(perm_string by_name) const @@ -136,12 +128,10 @@ Signal* ScopeBase::find_signal(perm_string by_name) const if (cur == new_signals_.end()) { cur = old_signals_.find(by_name); if (cur == old_signals_.end()) - return 0; - else - return cur->second; - } else { - return cur->second; + return NULL; // nothing found } + + return cur->second; } Variable* ScopeBase::find_variable(perm_string by_name) const @@ -150,12 +140,10 @@ Variable* ScopeBase::find_variable(perm_string by_name) const if (cur == new_variables_.end()) { cur = old_variables_.find(by_name); if (cur == old_variables_.end()) - return 0; - else - return cur->second; - } else { - return cur->second; + return 0; // nothing found } + + return cur->second; } const InterfacePort* ScopeBase::find_param(perm_string) const @@ -232,7 +220,6 @@ void ScopeBase::do_use_from(const ScopeBase*that) use_subprograms_[cur->first] = cur->second; } - for (map::const_iterator cur = that->cur_types_.begin() ; cur != that->cur_types_.end() ; ++ cur) { if (cur->second == 0) From 6f5addb1b7c19990306c5e4b61c8365f17ea783f Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 27 Aug 2015 16:32:37 +0200 Subject: [PATCH 03/24] vhdlpp: Fixed a gcc warning. --- vhdlpp/parse.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index ea948a1a8a..90e62f23b9 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -2586,7 +2586,7 @@ suffix { $$ = $1; } | K_all { //do not have now better idea than using char constant - $$ = strcpy(new char[strlen("all"+1)], "all"); + $$ = strdup("all"); } ; From 925827d2c263d26b9953ae88ab924a6d8a46f827 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 14 Sep 2015 14:04:23 +0200 Subject: [PATCH 04/24] vhdlpp: Escape quotation marks in emitted strings. --- vhdlpp/debug.cc | 8 ++------ vhdlpp/expression.cc | 4 +--- vhdlpp/expression.h | 8 ++++++-- vhdlpp/expression_emit.cc | 20 +++++++++++++++----- vhdlpp/expression_stream.cc | 11 ++++++++--- vhdlpp/sequential_emit.cc | 4 ++-- 6 files changed, 34 insertions(+), 21 deletions(-) diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index 71ca0abd4f..22fb312a64 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -415,12 +415,8 @@ void ExpRelation::dump(ostream&out, int indent) const void ExpString::dump(ostream&out, int indent) const { - out << setw(indent) << "" << "String \""; - for(vector::const_iterator it = value_.begin(); - it != value_.end(); ++it) - out << *it; - out << "\"" - << " at " << get_fileline() << endl; + out << setw(indent) << "" << "String \"" << value_; + out << "\"" << " at " << get_fileline() << endl; } void ExpUAbs::dump(ostream&out, int indent) const diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index 4361656a0c..b9573d1ef3 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -632,10 +632,8 @@ ExpShift::ExpShift(ExpShift::shift_t op, Expression*op1, Expression*op2) } ExpString::ExpString(const char* value) -: value_(strlen(value)) +: value_(value) { - for(size_t idx = 0; idx < value_.size(); idx += 1) - value_[idx] = value[idx]; } ExpString::~ExpString() diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index ba1a481206..ee609ae60d 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -796,13 +796,17 @@ class ExpString : public Expression { int emit(ostream&out, Entity*ent, ScopeBase*scope); bool is_primary(void) const; void dump(ostream&out, int indent = 0) const; - const std::vector& get_value() const { return value_; } + const std::string& get_value() const { return value_; } + + // Converts quotation marks (") to its escaped + // counterpart in SystemVerilog (\") + static std::string escape_quot(const std::string& str); private: int emit_as_array_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeArray*arr); private: - std::vector value_; + std::string value_; }; class ExpUAbs : public ExpUnary { diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 9ab2c66fac..09ac0654d7 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -916,11 +916,8 @@ int ExpString::emit(ostream& out, Entity*ent, ScopeBase*scope) return emit_as_array_(out, ent, scope, arr); } - out << "\""; - for(vector::const_iterator it = value_.begin() - ; it != value_.end(); ++it) - out << *it; - out << "\""; + out << "\"" << escape_quot(value_) << "\""; + return 0; } @@ -959,6 +956,19 @@ int ExpString::emit_as_array_(ostream& out, Entity*, ScopeBase*, const VTypeArra return errors; } +std::string ExpString::escape_quot(const std::string& str) +{ + size_t idx = 0; + string result(str); + + while((idx = result.find('"', idx)) != string::npos) { + result.replace(idx, 1, "\\\""); + idx += 2; + } + + return result; +} + int ExpUAbs::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; diff --git a/vhdlpp/expression_stream.cc b/vhdlpp/expression_stream.cc index 1321a3740f..d707fdcffe 100644 --- a/vhdlpp/expression_stream.cc +++ b/vhdlpp/expression_stream.cc @@ -272,10 +272,15 @@ void ExpShift::write_to_stream(ostream&out) const void ExpString::write_to_stream(ostream&fd) const { fd << "\""; - for(vector::const_iterator it = value_.begin(); - it != value_.end(); ++it) { - fd << *it; + + // Restore double quotation marks + for(string::const_iterator it = value_.begin(); it != value_.end(); ++it) { + if(*it == '"') + fd << "\"\""; + else + fd << *it; } + fd << "\""; } diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index 7148e2b52e..ec60fa3940 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -484,7 +484,7 @@ int ReportStmt::emit(ostream&out, Entity*, ScopeBase*) case UNSPECIFIED: ivl_assert(*this, false); break; } - out << msg_; + out << ExpString::escape_quot(msg_); out << " (" << get_fileline() << ")\");"; if(severity_ == FAILURE) @@ -497,7 +497,7 @@ int ReportStmt::emit(ostream&out, Entity*, ScopeBase*) void ReportStmt::write_to_stream(std::ostream&fd) { - fd << "report \"" << msg_ << "\"" << std::endl; + fd << "report \"" << ExpString::escape_quot(msg_) << "\"" << std::endl; fd << "severity "; switch(severity_) From 6fee37a6401cdbe38b5869cd6aafe7020f32cd35 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 15 Sep 2015 10:21:49 +0200 Subject: [PATCH 05/24] vhdlpp: Simplified regex to detect string literals. --- vhdlpp/lexor.lex | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/vhdlpp/lexor.lex b/vhdlpp/lexor.lex index 1cbda23c94..98916b05c9 100644 --- a/vhdlpp/lexor.lex +++ b/vhdlpp/lexor.lex @@ -111,9 +111,7 @@ time {integer}{W}*([fFpPnNuUmM]?[sS]) return CHARACTER_LITERAL; } -(\"([^\"]|(\"\"))*?\")|(\"[^\"]*\") { -/* first pattern: string literals with doubled quotation mark */ -/* second pattern: string literals without doubled quotation */ +(\"([^\"]|(\"\"))*?\") { yylval.text = escape_quot_and_dup(yytext); assert(yylval.text); return STRING_LITERAL; From b414733f34785add32d61686b467aecc36918ae8 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 18 Sep 2015 11:23:46 +0200 Subject: [PATCH 06/24] vhdlpp: std.textio & ieee.std_logic_textio functions implemented using VPI. --- driver/main.c | 1 + main.cc | 1 + verilog.spec | 2 + vpi/Makefile.in | 18 +- vpi/vhdl_textio.c | 943 ++++++++++++++++++++++++++++++++++++++++++++ vpi/vhdl_textio.sft | 9 + 6 files changed, 972 insertions(+), 2 deletions(-) create mode 100644 vpi/vhdl_textio.c create mode 100644 vpi/vhdl_textio.sft diff --git a/driver/main.c b/driver/main.c index 810a2de904..2990d47062 100644 --- a/driver/main.c +++ b/driver/main.c @@ -1072,6 +1072,7 @@ int main(int argc, char **argv) how to handle them. */ fprintf(iconfig_file, "sys_func:%s%csystem.sft\n", base, sep); fprintf(iconfig_file, "sys_func:%s%cvhdl_sys.sft\n", base, sep); + fprintf(iconfig_file, "sys_func:%s%cvhdl_textio.sft\n", base, sep); /* If verilog-2005/09/12 is enabled or icarus-misc or verilog-ams, * then include the v2005_math library. */ diff --git a/main.cc b/main.cc index 1b11f4f877..66dd107659 100644 --- a/main.cc +++ b/main.cc @@ -832,6 +832,7 @@ int main(int argc, char*argv[]) // Start the module list with the base system module. add_vpi_module("system"); add_vpi_module("vhdl_sys"); + add_vpi_module("vhdl_textio"); flags["-o"] = strdup("a.out"); min_typ_max_flag = TYP; diff --git a/verilog.spec b/verilog.spec index 97c962b14f..97a0e3c1a3 100644 --- a/verilog.spec +++ b/verilog.spec @@ -102,6 +102,8 @@ rm -rf $RPM_BUILD_ROOT %attr(-,root,root) %{_libdir}/ivl%{suff}/v2009.vpi %attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl_sys.sft %attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl_sys.vpi +%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl_textio.sft +%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl_textio.vpi %attr(-,root,root) %{_libdir}/ivl%{suff}/vpi_debug.vpi %attr(-,root,root) %{_libdir}/ivl%{suff}/cadpli.vpl %attr(-,root,root) %{_libdir}/libvpi%{suff}.a diff --git a/vpi/Makefile.in b/vpi/Makefile.in index 30e537784d..4a5502902b 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -77,9 +77,11 @@ V2009 = v2009_table.o v2009_array.o v2009_enum.o v2009_string.o VHDL_SYS = vhdl_table.o +VHDL_TEXTIO = vhdl_textio.o sys_priv.o + VPI_DEBUG = vpi_debug.o -all: dep system.vpi va_math.vpi v2005_math.vpi v2009.vpi vhdl_sys.vpi vpi_debug.vpi $(ALL32) +all: dep system.vpi va_math.vpi v2005_math.vpi v2009.vpi vhdl_sys.vpi vhdl_textio.vpi vpi_debug.vpi $(ALL32) check: all @@ -88,7 +90,7 @@ clean: rm -f sdf_lexor.c sdf_parse.c sdf_parse.output sdf_parse.h rm -f table_mod_parse.c table_mod_parse.h table_mod_parse.output rm -f table_mod_lexor.c - rm -f va_math.vpi v2005_math.vpi v2009.vpi vhdl_sys.vpi vpi_debug.vpi + rm -f va_math.vpi v2005_math.vpi v2009.vpi vhdl_sys.vpi vhdl_textio.vpi vpi_debug.vpi distclean: clean rm -f Makefile config.log @@ -163,6 +165,9 @@ va_math.vpi: $V ../vvp/libvpi.a vhdl_sys.vpi: $(VHDL_SYS) ../vvp/libvpi.a $(CC) @shared@ -o $@ $(VHDL_SYS) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS) +vhdl_textio.vpi: $(VHDL_TEXTIO) ../vvp/libvpi.a + $(CC) @shared@ -o $@ $(VHDL_TEXTIO) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS) + vpi_debug.vpi: $(VPI_DEBUG) ../vvp/libvpi.a $(CC) @shared@ -o $@ $(VPI_DEBUG) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS) @@ -177,6 +182,7 @@ install: all installdirs \ $(vpidir)/v2005_math.vpi $(vpidir)/v2005_math.sft \ $(vpidir)/v2009.vpi $(vpidir)/v2009.sft \ $(vpidir)/vhdl_sys.vpi $(vpidir)/vhdl_sys.sft \ + $(vpidir)/vhdl_textio.vpi $(vpidir)/vhdl_textio.sft \ $(vpidir)/vpi_debug.vpi $(vpidir)/system.vpi: ./system.vpi @@ -209,6 +215,12 @@ $(vpidir)/vhdl_sys.vpi: ./vhdl_sys.vpi $(vpidir)/vhdl_sys.sft: vhdl_sys.sft $(INSTALL_DATA) $< "$(DESTDIR)$@" +$(vpidir)/vhdl_textio.vpi: ./vhdl_textio.vpi + $(INSTALL_PROGRAM) ./vhdl_textio.vpi "$(DESTDIR)$(vpidir)/vhdl_textio.vpi" + +$(vpidir)/vhdl_textio.sft: vhdl_textio.sft + $(INSTALL_DATA) $< "$(DESTDIR)$@" + $(vpidir)/vpi_debug.vpi: ./vpi_debug.vpi $(INSTALL_PROGRAM) ./vpi_debug.vpi "$(DESTDIR)$(vpidir)/vpi_debug.vpi" @@ -226,6 +238,8 @@ uninstall: rm -f "$(DESTDIR)$(vpidir)/v2009.sft" rm -f "$(DESTDIR)$(vpidir)/vhdl_sys.vpi" rm -f "$(DESTDIR)$(vpidir)/vhdl_sys.sft" + rm -f "$(DESTDIR)$(vpidir)/vhdl_textio.vpi" + rm -f "$(DESTDIR)$(vpidir)/vhdl_textio.sft" rm -f "$(DESTDIR)$(vpidir)/vpi_debug.vpi" -include $(patsubst %.o, dep/%.d, $O) diff --git a/vpi/vhdl_textio.c b/vpi/vhdl_textio.c new file mode 100644 index 0000000000..f770123a8f --- /dev/null +++ b/vpi/vhdl_textio.c @@ -0,0 +1,943 @@ +/* + * Copyright (c) 2015 CERN + * @author Maciej Suminski + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** + * The following VPI module implements some of the functions available + * in std.textio library. + * + * Type counterparts: + * VHDL SystemVerilog + * ------------------------------ + * LINE string (line of text, in VHDL it is a pointer to string) + * TEXT int (file handle) + * + * Some of functions offered by std.textio library are not implemented here, + * as they can be directly replaced with SystemVerilog system functions. + * + * VHDL SystemVerilog + * -------------------------------------- + * FILE_CLOSE(file F: TEXT) $fclose(fd) + * ENDFILE(file F: TEXT) $feof(fd) + * + * Procedures: + * HREAD (L: inout LINE; VALUE: out BIT_VECTOR) + * HWRITE (L: inout LINE; VALUE: out BIT_VECTOR) + * are handled with $ivlh_read/write() using FORMAT_HEX parameter (see format_t enum). + */ + +# include "sys_priv.h" +# include "vpi_config.h" +# include "vpi_user.h" +# include +# include +# include +# include "ivl_alloc.h" + +/* additional parameter values to distinguish between integer, boolean and + * time types or to use hex format */ +enum format_t { FORMAT_STD, FORMAT_BOOL, FORMAT_TIME, FORMAT_HEX, FORMAT_STRING }; + +enum file_mode_t { FILE_MODE_READ, FILE_MODE_WRITE, FILE_MODE_APPEND, FILE_MODE_LAST }; + +/* bits per vector, in a single s_vpi_vecval struct */ +static const size_t BPW = 8 * sizeof(PLI_INT32); + +static int is_integer_var(vpiHandle obj) +{ + PLI_INT32 type = vpi_get(vpiType, obj); + + return (type == vpiIntegerVar || type == vpiShortIntVar || + type == vpiIntVar || type == vpiLongIntVar); +} + +static void show_error_line(vpiHandle callh) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); +} + +static void show_warning_line(vpiHandle callh) { + vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); +} + +/* sets a single bit value in a bit/logic vector */ +static int set_vec_val(s_vpi_vecval* vector, char value, int idx) { + s_vpi_vecval*v = &vector[idx / BPW]; + PLI_INT32 bit = idx % BPW; + + switch(toupper(value)) { + case '0': + v->bval &= ~(1 << bit); + v->aval &= ~(1 << bit); + break; + + case '1': + v->bval &= ~(1 << bit); + v->aval |= (1 << bit); + break; + + case 'Z': + v->bval |= (1 << bit); + v->aval &= ~(1 << bit); + break; + + case 'X': + v->bval |= (1 << bit); + v->aval |= (1 << bit); + break; + + default: + return 1; + } + + return 0; +} + +/* Converts a string of characters to a vector in s_vpi_value struct. + * Returns number of processed characters, 0 in case of failure. + * string is the data to be converted. + * val is the target s_vpi_value struct. + * var is the variable that is converted (to obtain size & type [2/4-state]). + */ +static int read_vector(const char *string, s_vpi_value *val, vpiHandle var) +{ +#if 0 + /* It could be easier to simply use val.format = vpiBinStrVal + * but there is no way to check if processing went fine */ + val.format = vpiBinStrVal; + val.value.str = string; + processed_chars = size; +#endif + /* Vector size (==1 for scalars) */ + int size = vpi_get(vpiSize, var); + + /* Number of required s_vpi_vecval structs to store the result */ + int words = (size + BPW - 1) / BPW; /* == ceil(size / BPW) */ + int len = strlen(string); + + val->format = vpiVectorVal; /* it also covers scalars */ + val->value.vector = calloc(words, sizeof(s_vpi_vecval)); + + /* Skip spaces in the beginning */ + int skipped = 0; + while(*string && *string == ' ') { + --len; + ++string; + ++skipped; + } + + /* Process bits */ + int p; + for(p = 0; p < size && p < len; ++p) { + if(set_vec_val(val->value.vector, string[p], size - p - 1)) { + free(val->value.vector); /* error */ + return 0; + } + } + + /* 2-logic variables cannot hold X or Z values, so change them to 0 */ + if(vpi_get(vpiType, var) == vpiBitVar) { + for(int i = 0; i < words; ++i) { + val->value.vector[i].aval &= ~val->value.vector[i].bval; + val->value.vector[i].bval = 0; + } + } + + return p + skipped; +} + +/* Converts a string of characters to a time value, stored in vector filed of + * s_vpi_value struct. + * Returns number of processed characters, 0 in case of failure. + * string is the data to be converted. + * val is the target s_vpi_value struct. + * scope_unit is the time unit used in the scope (-3 for millisecond, + * -6 for microsecond, etc.) + */ +static int read_time(const char *string, s_vpi_value *val, PLI_INT32 scope_unit) { + PLI_UINT64 period; + char units[2]; + int time_unit, processed_chars; + + if(sscanf(string, "%ld %2s%n", &period, units, &processed_chars) != 2) + return 0; + + if(!strncasecmp(units, "fs", 2)) + time_unit = -15; + else if(!strncasecmp(units, "ps", 2)) + time_unit = -12; + else if(!strncasecmp(units, "ns", 2)) + time_unit = -9; + else if(!strncasecmp(units, "us", 2)) + time_unit = -6; + else if(!strncasecmp(units, "ms", 2)) + time_unit = -3; + else if(!strncasecmp(units, "s", 1)) + time_unit = 0; + else + return 0; + + /* Scale the time units to the one used in the scope */ + int scale_diff = time_unit - scope_unit; + + if(scale_diff > 0) { + for(int i = 0; i < scale_diff; ++i) + period *= 10; + } else { + for(int i = 0; i < -scale_diff; ++i) + period /= 10; + } + + /* vpiTimeVal format is not handled at the moment, + * so return the read value as a vector*/ + val->format = vpiVectorVal; + val->value.vector = calloc(2, sizeof(s_vpi_vecval)); + memset(val->value.vector, 0, 2 * sizeof(s_vpi_vecval)); + + val->value.vector[1].aval = (PLI_UINT32) (period >> 32); + val->value.vector[0].aval = (PLI_UINT32) period; + + return processed_chars; +} + +static int read_string(const char *string, s_vpi_value *val) { + char buf[1024]; + int processed_chars; + + if(sscanf(string, "%1024s%n", buf, &processed_chars) != 1) + return 0; + + val->format = vpiStringVal; + val->value.str = strndup(buf, processed_chars); + + return processed_chars; +} + +static int write_time(char *string, const s_vpi_value* val, + size_t width, PLI_INT32 scope_unit) { + char prefix = 0; + PLI_UINT64 period; + + switch(val->format) { + case vpiIntVal: + period = val->value.integer; + break; + + case vpiVectorVal: + period = val->value.vector[0].aval; + + if(width > BPW) + period |= (PLI_UINT64)(val->value.vector[1].aval) << 32; + break; + + default: + return 1; + } + + /* Handle the case when the time unit base is 10 or 100 */ + int remainder = scope_unit % -3; + if(remainder) { + remainder += 3; + scope_unit -= remainder; + + while(remainder--) + period *= 10; + } + + switch(scope_unit) { + case -15: prefix = 'f'; break; + case -12: prefix = 'p'; break; + case -9: prefix = 'n'; break; + case -6: prefix = 'u'; break; + case -3: prefix = 'm'; break; + } + + if(prefix) + sprintf(string, "%ld %cs", period, prefix); + else + sprintf(string, "%ld s", period); + + return 0; +} + +/* slightly modified sys_fopen_compiletf */ +static PLI_INT32 ivlh_file_open_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv; + assert(callh != 0); + + argv = vpi_iterate(vpiArgument, callh); + + /* Check that there is a file name argument and that it is a string. */ + if (argv == 0) { + show_error_line(callh); + vpi_printf("%s requires a string file name argument.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + + if(!is_integer_var(vpi_scan(argv))) { + show_error_line(callh); + vpi_printf("%s's first argument has to be an integer variable (file handle).\n", name); + vpi_control(vpiFinish, 1); + } + + if(!is_string_obj(vpi_scan(argv))) { + show_error_line(callh); + vpi_printf("%s's second argument argument must be a string (file name).\n", name); + vpi_control(vpiFinish, 1); + } + + /* When provided, the type argument must be a string. */ + if(!vpi_scan(argv)) { + show_error_line(callh); + vpi_printf("%s's third argument must be an integer (open mode).\n", name); + vpi_control(vpiFinish, 1); + } + + /* Make sure there are no extra arguments. */ + check_for_extra_args(argv, callh, name, "three arguments", 1); + + return 0; +} + +/* procedure FILE_MODE(file F: TEXT; External_Name; in STRING; + Open_Kind: in FILE_MODE_KIND := READ_MODE); */ +/* slightly modified sys_fopen_calltf */ +static PLI_INT32 ivlh_file_open_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + s_vpi_value val; + int mode; + char *fname; + + vpiHandle fhandleh = vpi_scan(argv); + vpiHandle fnameh = vpi_scan(argv); + vpiHandle modeh = vpi_scan(argv); + + /* Get the mode handle */ + val.format = vpiIntVal; + vpi_get_value(modeh, &val); + mode = val.value.integer; + vpi_free_object(argv); + + if(mode < 0 || mode >= FILE_MODE_LAST) { + show_error_line(callh); + vpi_printf("%s's file open mode argument is invalid.\n", name); + return 0; + } + + fname = get_filename(callh, name, fnameh); + + if(fname == 0) { + show_error_line(callh); + vpi_printf("%s's could not obtain the file name.\n", name); + return 0; + } + + /* Open file and save the handle */ + switch(mode) { + case FILE_MODE_READ: + val.value.integer = vpi_fopen(fname, "r"); + break; + + case FILE_MODE_WRITE: + val.value.integer = vpi_fopen(fname, "w"); + break; + + case FILE_MODE_APPEND: + val.value.integer = vpi_fopen(fname, "a"); + break; + } + + val.format = vpiIntVal; + vpi_put_value(fhandleh, &val, 0, vpiNoDelay); + free(fname); + + return 0; +} + +static PLI_INT32 ivlh_readwriteline_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle arg; + + /* Check that there are two arguments and that the first is an + integer (file handle) and that the second is string. */ + if(argv == 0) { + show_error_line(callh); + vpi_printf("%s requires two arguments.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + + arg = vpi_scan(argv); + if(!arg || !is_integer_var(arg)) { + show_error_line(callh); + vpi_printf("%s's first argument must be an integer variable (file handle).\n", name); + vpi_control(vpiFinish, 1); + } + + arg = vpi_scan(argv); + if(!arg || !is_string_obj(arg)) { + show_error_line(callh); + vpi_printf("%s's second argument must be a string.\n", name); + vpi_control(vpiFinish, 1); + } + + /* Make sure there are no extra arguments. */ + check_for_extra_args(argv, callh, name, "two arguments", 0); + + return 0; +} + +/* procedure READLINE (file F: TEXT; L: inout LINE); */ +/* slightly modified sys_fgets_calltf */ +static PLI_INT32 ivlh_readline_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle stringh, arg; + s_vpi_value val; + PLI_UINT32 fd; + FILE *fp; + char *text; + const int BUF_SIZE = 1024; + char buf[BUF_SIZE]; + + /* Get the file descriptor. */ + arg = vpi_scan(argv); + val.format = vpiIntVal; + vpi_get_value(arg, &val); + fd = val.value.integer; + + /* Get the string handle. */ + stringh = vpi_scan(argv); + vpi_free_object(argv); + + /* Return zero if this is not a valid fd. */ + fp = vpi_get_file(fd); + if(!fp) { + show_warning_line(callh); + vpi_printf("invalid file descriptor (0x%x) given to %s.\n", + (unsigned int)fd, name); + return 0; + } + + /* Read in the bytes. Return 0 if there was an error. */ + if(fgets(buf, BUF_SIZE, fp) == 0) { + show_error_line(callh); + vpi_printf("%s reading past the end of file.\n", name); + + return 0; + } + + int len = strlen(buf); + + if(len == 0) { + show_error_line(callh); + vpi_printf("%s read 0 bytes.\n", name); + return 0; + } else if(len == BUF_SIZE - 1) { + show_warning_line(callh); + vpi_printf("%s has reached the buffer limit, part of the " + "processed string might have been skipped.\n", name); + } + + /* Return the characters to the register. */ + text = strndup(buf, len - 1); /* skip the newline character */ + val.format = vpiStringVal; + val.value.str = text; + vpi_put_value(stringh, &val, 0, vpiNoDelay); + free(text); + + return 0; +} + +/* procedure WRITELINE (file F: TEXT; L: inout LINE); */ +/* slightly modified sys_fgets_calltf */ +static PLI_INT32 ivlh_writeline_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle stringh, arg; + s_vpi_value val; + PLI_UINT32 fd; + FILE *fp; + char *empty; + + /* Get the file descriptor. */ + arg = vpi_scan(argv); + val.format = vpiIntVal; + vpi_get_value(arg, &val); + fd = val.value.integer; + + /* Get the string contents. */ + stringh = vpi_scan(argv); + val.format = vpiStringVal; + vpi_get_value(stringh, &val); + + vpi_free_object(argv); + + /* Return zero if this is not a valid fd. */ + fp = vpi_get_file(fd); + if(!fp) { + show_warning_line(callh); + vpi_printf("invalid file descriptor (0x%x) given to %s.\n", + (unsigned int)fd, name); + return 0; + } + + fprintf(fp, "%s\n", val.value.str); + + /* Clear the written string */ + empty = strdup(""); + val.format = vpiStringVal; + val.value.str = empty; + vpi_put_value(stringh, &val, 0, vpiNoDelay); + free(empty); + + return 0; +} + +static PLI_INT32 ivlh_read_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle arg; + + if(argv == 0) { + show_error_line(callh); + vpi_printf("%s requires three arguments.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + + arg = vpi_scan(argv); + if(!arg || !is_string_obj(arg)) { + show_error_line(callh); + vpi_printf("%s's first argument must be a string.\n", name); + vpi_control(vpiFinish, 1); + } + + arg = vpi_scan(argv); + if(!arg || is_constant_obj(arg)) { + show_error_line(callh); + vpi_printf("%s's second argument must be a variable.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + + arg = vpi_scan(argv); + if(!arg) { + show_error_line(callh); + vpi_printf("%s's third argument must be an integer.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + /* Make sure there are no extra arguments. */ + check_for_extra_args(argv, callh, name, "three arguments", 0); + + return 0; +} + +/* procedure READ (L: inout LINE; + VALUE: out BIT/BIT_VECTOR/BOOLEAN/CHARACTER/INTEGER/REAL/STRING/TIME); */ +static PLI_INT32 ivlh_read_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle stringh, varh, formath; + s_vpi_value val; + PLI_INT32 type, format; + char *string = 0; + int processed_chars = 0, fail = 0; + + /* Get the string */ + stringh = vpi_scan(argv); + val.format = vpiStringVal; + vpi_get_value(stringh, &val); + + /* Get the destination variable */ + varh = vpi_scan(argv); + type = vpi_get(vpiType, varh); + + if(strlen(val.value.str) == 0) { + show_error_line(callh); + vpi_printf("%s cannot read from an empty string.\n", name); + return 0; + } + + string = strdup(val.value.str); + + /* Get the format (see enum format_t) */ + formath = vpi_scan(argv); + val.format = vpiIntVal; + vpi_get_value(formath, &val); + format = val.value.integer; + vpi_free_object(argv); + + switch(format) { + case FORMAT_STD: + switch(type) { + /* TODO longint is 64-bit, so it has to be handled by vector */ + /*case vpiLongIntVar:*/ + case vpiShortIntVar: + case vpiIntVar: + case vpiByteVar: + case vpiIntegerVar: + val.format = vpiIntVal; + if(sscanf(string, "%d%n", &val.value.integer, &processed_chars) != 1) + fail = 1; + break; + + case vpiBitVar: /* bit, bit vector */ + case vpiLogicVar: /* ==vpiReg time, logic, logic vector */ + processed_chars = read_vector(string, &val, varh); + break; + + case vpiRealVar: + val.format = vpiRealVal; + if(sscanf(string, "%lf%n", &val.value.real, &processed_chars) != 1) + fail = 1; + break; + + case vpiStringVar: + processed_chars = read_string(string, &val); + break; + + default: + fail = 1; + show_warning_line(callh); + vpi_printf("%s does not handle such type (%d).\n", name, type); + break; + } + break; + + case FORMAT_BOOL: + { + char buf[5]; + + val.format = vpiIntVal; + if(sscanf(string, "%5s%n", buf, &processed_chars) == 1) + { + if(!strncasecmp(buf, "true", 4)) + val.value.integer = 1; + else if(!strncasecmp(buf, "false", 5)) + val.value.integer = 0; + else + fail = 1; + } + } + break; + + case FORMAT_TIME: + val.format = vpiIntVal; + processed_chars = read_time(string, &val, vpi_get(vpiTimeUnit, callh)); + break; + + case FORMAT_HEX: + val.format = vpiIntVal; + if(sscanf(string, "%x%n", &val.value.integer, &processed_chars) != 1) + fail = 1; + break; + + case FORMAT_STRING: + processed_chars = read_string(string, &val); + break; + } + + if(processed_chars == 0) { + show_error_line(callh); + vpi_printf("%s could not read a valid value.\n", name); + fail = 1; + } else if(val.format == vpiStringVar && processed_chars == 1024) { + show_warning_line(callh); + vpi_printf("%s has reached the buffer limit, part of the " + "processed string might have been skipped.\n", name); + } + + if(!fail) { + assert(processed_chars > 0); + + /* Store the read value */ + vpi_put_value(varh, &val, 0, vpiNoDelay); + + /* Clean up */ + if(val.format == vpiStringVar) + free(val.value.str); + else if(val.format == vpiVectorVal) + free(val.value.vector); + + /* Strip the read token from the string */ + char* tmp = strdup(&string[processed_chars]); + val.format = vpiStringVal; + val.value.str = tmp; + vpi_put_value(stringh, &val, 0, vpiNoDelay); + free(tmp); + } else { + show_error_line(callh); + vpi_printf("%s failed.\n", name); + /*vpi_control(vpiFinish, 1);*/ + } + + free(string); + + return 0; +} + +static PLI_INT32 ivlh_write_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle arg; + + if(argv == 0) { + show_error_line(callh); + vpi_printf("%s requires three arguments.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + + arg = vpi_scan(argv); + if(!arg || !is_string_obj(arg)) { + show_error_line(callh); + vpi_printf("%s's first argument must be a string.\n", name); + vpi_control(vpiFinish, 1); + } + + arg = vpi_scan(argv); + if(!arg) { + show_error_line(callh); + vpi_printf("%s requires three arguments.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + + arg = vpi_scan(argv); + if(!arg) { + show_error_line(callh); + vpi_printf("%s's third argument must be an integer.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + /* Make sure there are no extra arguments. */ + check_for_extra_args(argv, callh, name, "three arguments", 0); + + return 0; +} + +/*procedure WRITE (L: inout LINE; + VALUE: in BIT/BIT_VECTOR/BOOLEAN/CHARACTER/INTEGER/REAL/STRING/TIME); + JUSTIFIED: in SIDE:= RIGHT; FIELD: in WIDTH := 0); */ +/* JUSTIFIED & FIELD are not handled at the moment */ +static PLI_INT32 ivlh_write_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle stringh, varh, formath; + s_vpi_value val; + PLI_INT32 type, format; + char *string = 0; + int fail = 0, res = 0; + const int BUF_SIZE = 1024; + char buf[BUF_SIZE]; + + /* Get the string */ + stringh = vpi_scan(argv); + val.format = vpiStringVal; + vpi_get_value(stringh, &val); + string = strdup(val.value.str); + + /* Get the destination variable */ + varh = vpi_scan(argv); + type = vpi_get(vpiType, varh); + + /* Get the format (see enum format_t) */ + formath = vpi_scan(argv); + val.format = vpiIntVal; + vpi_get_value(formath, &val); + format = val.value.integer; + vpi_free_object(argv); + + /* Convert constant types to variable types */ + if(type == vpiConstant) { + type = vpi_get(vpiConstType, varh); + + switch(type) { + case vpiRealConst: + type = vpiRealVar; + break; + + case vpiStringConst: + type = vpiStringVar; + break; + + case vpiDecConst: + case vpiBinaryConst: + case vpiOctConst: + case vpiHexConst: + type = vpiIntVar; + break; + } + } + + switch(format) { + case FORMAT_STD: + switch(type) { + /* TODO longint is 64-bit, so it has to be handled by vector */ + /*case vpiLongIntVar:*/ + case vpiShortIntVar: + case vpiIntVar: + case vpiByteVar: + case vpiIntegerVar: + val.format = vpiIntVal; + vpi_get_value(varh, &val); + res = snprintf(buf, BUF_SIZE, "%s%d", string, val.value.integer); + break; + + case vpiBitVar: /* bit, bit vector */ + case vpiLogicVar: /* ==vpiReg time, logic, logic vector */ + val.format = vpiBinStrVal; + vpi_get_value(varh, &val); + + /* VHDL stores X/Z values uppercase, so follow the rule */ + for(size_t i = 0; i< strlen(val.value.str); ++i) + val.value.str[i] = toupper(val.value.str[i]); + + res = snprintf(buf, BUF_SIZE, "%s%s", string, val.value.str); + break; + + case vpiRealVar: + val.format = vpiRealVal; + vpi_get_value(varh, &val); + res = snprintf(buf, BUF_SIZE, "%s%lf", string, val.value.real); + break; + + case vpiStringVar: + val.format = vpiStringVal; + vpi_get_value(varh, &val); + res = snprintf(buf, BUF_SIZE, "%s%s", string, val.value.str); + break; + + default: + fail = 1; + show_warning_line(callh); + vpi_printf("%s does not handle such type (%d).\n", name, type); + break; + } + break; + + case FORMAT_BOOL: + val.format = vpiIntVal; + vpi_get_value(varh, &val); + res = snprintf(buf, BUF_SIZE, "%s%s", string, + val.value.integer ? "TRUE" : "FALSE"); + break; + + case FORMAT_TIME: + { + char tmp[64]; + + val.format = vpiIntVal; + vpi_get_value(varh, &val); + + if(write_time(tmp, &val, vpi_get(vpiSize, varh), vpi_get(vpiTimeUnit, callh))) { + fail = 1; + break; + } + + res = snprintf(buf, BUF_SIZE, "%s%s", string, tmp); + } + break; + + case FORMAT_HEX: + val.format = vpiIntVal; + vpi_get_value(varh, &val); + res = snprintf(buf, BUF_SIZE, "%s%X", string, val.value.integer); + break; + + case FORMAT_STRING: + val.format = vpiStringVal; + vpi_get_value(varh, &val); + res = snprintf(buf, BUF_SIZE, "%s%s", string, val.value.str); + break; + } + + if(res > BUF_SIZE) + fail = 1; + + if(!fail) { + /* Strip the read token from the string */ + char* tmp = strndup(buf, BUF_SIZE); + val.format = vpiStringVal; + val.value.str = tmp; + vpi_put_value(stringh, &val, 0, vpiNoDelay); + free(tmp); + } else { + show_error_line(callh); + vpi_printf("%s failed.\n", name); + /*vpi_control(vpiFinish, 1);*/ + } + + free(string); + + return 0; +} + +static void vhdl_register(void) +{ + vpiHandle res; + + s_vpi_systf_data tf_data[] = { + { vpiSysTask, 0, "$ivlh_file_open", + ivlh_file_open_calltf, ivlh_file_open_compiletf, 0, + "$ivlh_file_open" }, + + { vpiSysTask, 0, "$ivlh_readline", + ivlh_readline_calltf, ivlh_readwriteline_compiletf, 0, + "$ivlh_readline" }, + + { vpiSysTask, 0, "$ivlh_writeline", + ivlh_writeline_calltf, ivlh_readwriteline_compiletf, 0, + "$ivlh_writeline" }, + + { vpiSysTask, 0, "$ivlh_read", + ivlh_read_calltf, ivlh_read_compiletf, 0, + "$ivlh_read" }, + + { vpiSysTask, 0, "$ivlh_write", + ivlh_write_calltf, ivlh_write_compiletf, 0, + "$ivlh_write" }, + }; + + for(unsigned int i = 0; i < sizeof(tf_data) / sizeof(s_vpi_systf_data); ++i) { + res = vpi_register_systf(&tf_data[i]); + vpip_make_systf_system_defined(res); + } +} + +void (*vlog_startup_routines[])(void) = { + vhdl_register, + 0 +}; diff --git a/vpi/vhdl_textio.sft b/vpi/vhdl_textio.sft new file mode 100644 index 0000000000..f2fe46cf13 --- /dev/null +++ b/vpi/vhdl_textio.sft @@ -0,0 +1,9 @@ +$ivlh_file_open vpiSysFuncVoid + +$ivlh_readline vpiSysFuncVoid +$ivlh_writeline vpiSysFuncVoid + +$ivlh_read vpiSysFuncVoid +$ivlh_write vpiSysFuncVoid +$ivlh_hread vpiSysFuncVoid +$ivlh_hwrite vpiSysFuncVoid From ba3c07a59aec7b59171451e47cd88662327ac195 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 22 Sep 2015 14:32:29 +0200 Subject: [PATCH 07/24] vhdlpp: CHARACTER type is converted to bit[7:0] instead of byte. This way it is possible to have limited size strings. Previously they were translated to unpacked array of bytes, which cannot be assigned as it was a string. --- vhdlpp/expression_emit.cc | 2 +- vhdlpp/std_types.cc | 2 +- vhdlpp/std_types.h | 2 +- vhdlpp/vtype.cc | 6 ------ vhdlpp/vtype.h | 2 +- vhdlpp/vtype_emit.cc | 3 --- vhdlpp/vtype_stream.cc | 3 --- 7 files changed, 4 insertions(+), 16 deletions(-) diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 09ac0654d7..8874da8e67 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -931,7 +931,7 @@ int ExpString::emit_as_array_(ostream& out, Entity*, ScopeBase*, const VTypeArra // Detect the special case that this is an array of // CHARACTER. In this case, emit at a Verilog string. - if (etype->type()==VTypePrimitive::CHARACTER) { + if (arr->element_type() == &primitive_CHARACTER) { vector tmp (value_.size() + 3); tmp[0] = '"'; memcpy(&tmp[1], &value_[0], value_.size()); diff --git a/vhdlpp/std_types.cc b/vhdlpp/std_types.cc index 20acb42a63..311c74f1e4 100644 --- a/vhdlpp/std_types.cc +++ b/vhdlpp/std_types.cc @@ -30,11 +30,11 @@ const VTypePrimitive primitive_INTEGER(VTypePrimitive::INTEGER); const VTypePrimitive primitive_NATURAL(VTypePrimitive::NATURAL); const VTypePrimitive primitive_REAL(VTypePrimitive::REAL); const VTypePrimitive primitive_STDLOGIC(VTypePrimitive::STDLOGIC, true); -const VTypePrimitive primitive_CHARACTER(VTypePrimitive::CHARACTER); const VTypePrimitive primitive_TIME(VTypePrimitive::TIME); VTypeDef type_BOOLEAN(perm_string::literal("boolean")); +const VTypeArray primitive_CHARACTER(&primitive_BIT, 7, 0); const VTypeArray primitive_BIT_VECTOR(&primitive_BIT, vector (1)); const VTypeArray primitive_BOOL_VECTOR(&type_BOOLEAN, vector (1)); const VTypeArray primitive_STDLOGIC_VECTOR(&primitive_STDLOGIC, vector (1)); diff --git a/vhdlpp/std_types.h b/vhdlpp/std_types.h index b38003cf4f..72bfa20759 100644 --- a/vhdlpp/std_types.h +++ b/vhdlpp/std_types.h @@ -35,11 +35,11 @@ extern const VTypePrimitive primitive_INTEGER; extern const VTypePrimitive primitive_NATURAL; extern const VTypePrimitive primitive_REAL; extern const VTypePrimitive primitive_STDLOGIC; -extern const VTypePrimitive primitive_CHARACTER; extern const VTypePrimitive primitive_TIME; extern VTypeDef type_BOOLEAN; +extern const VTypeArray primitive_CHARACTER; extern const VTypeArray primitive_BIT_VECTOR; extern const VTypeArray primitive_BOOL_VECTOR; extern const VTypeArray primitive_STDLOGIC_VECTOR; diff --git a/vhdlpp/vtype.cc b/vhdlpp/vtype.cc index 0e6c1b47db..730eb00a91 100644 --- a/vhdlpp/vtype.cc +++ b/vhdlpp/vtype.cc @@ -58,9 +58,6 @@ void VTypePrimitive::show(ostream&out) const case BIT: out << "BIT"; break; - case CHARACTER: - out << "CHARACTER"; - break; case INTEGER: out << "INTEGER"; break; @@ -90,9 +87,6 @@ int VTypePrimitive::get_width(ScopeBase*) const case NATURAL: return 32; - case CHARACTER: - return 8; - default: std::cerr << "sorry: primitive type " << type_ << " has no get_width() implementation." << std::endl; diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index f9ffc2186c..bf4968b14d 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -156,7 +156,7 @@ class VTypeERROR : public VType { class VTypePrimitive : public VType { public: - enum type_t { BIT, INTEGER, NATURAL, REAL, STDLOGIC, CHARACTER, TIME }; + enum type_t { BIT, INTEGER, NATURAL, REAL, STDLOGIC, TIME }; public: VTypePrimitive(type_t tt, bool packed = false); diff --git a/vhdlpp/vtype_emit.cc b/vhdlpp/vtype_emit.cc index 35d3ef2e64..9287a46c06 100644 --- a/vhdlpp/vtype_emit.cc +++ b/vhdlpp/vtype_emit.cc @@ -163,9 +163,6 @@ int VTypePrimitive::emit_primitive_type(ostream&out) const case REAL: out << "real"; break; - case CHARACTER: - out << "byte"; - break; case TIME: out << "time"; break; diff --git a/vhdlpp/vtype_stream.cc b/vhdlpp/vtype_stream.cc index 1394ccd060..0b4a12f1e2 100644 --- a/vhdlpp/vtype_stream.cc +++ b/vhdlpp/vtype_stream.cc @@ -161,9 +161,6 @@ void VTypePrimitive::write_to_stream(ostream&fd) const case STDLOGIC: fd << "std_logic"; break; - case CHARACTER: - fd << "character"; - break; case TIME: fd << "time"; break; From 637d7c963306a7b4d0cc295b5621d8b0b407a9a6 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 22 Sep 2015 14:34:47 +0200 Subject: [PATCH 08/24] vhdlpp: Special handling for STRING type during type emission. --- vhdlpp/vtype_emit.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/vhdlpp/vtype_emit.cc b/vhdlpp/vtype_emit.cc index 9287a46c06..c33c68304a 100644 --- a/vhdlpp/vtype_emit.cc +++ b/vhdlpp/vtype_emit.cc @@ -22,6 +22,7 @@ # include "vtype.h" # include "expression.h" +# include "std_types.h" # include # include # include @@ -66,6 +67,14 @@ int VTypeArray::emit_def(ostream&out, perm_string name) const if (base) { assert(dimensions() == 1); + // If this is a string type without any boundaries specified, then + // there is a direct counterpart in SV called.. 'string' + if(this == &primitive_STRING) { + out << "string"; + emit_name(out, name); + return errors; + } + base->emit_def(out, empty_perm_string); if (signed_flag_) out << " signed"; From 46ea9e6954007f9613718a34521e94674eb9a9ca Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 23 Sep 2015 11:46:29 +0200 Subject: [PATCH 09/24] vhdlpp: Out & inout arguments in subprogram calls are turned to registers. Otherwise it is not possible to modify their values in subprograms. Argument elaboration has been moved to a separate function, so now it is common for procedure and function calls. --- vhdlpp/entity.h | 4 ++++ vhdlpp/expression.h | 4 ++++ vhdlpp/expression_elaborate.cc | 35 ++++++++++++++++++++++++++-------- vhdlpp/sequential_elaborate.cc | 9 ++------- vhdlpp/subprogram.cc | 14 ++++++++++++-- vhdlpp/subprogram.h | 1 + 6 files changed, 50 insertions(+), 17 deletions(-) diff --git a/vhdlpp/entity.h b/vhdlpp/entity.h index 4faefe4415..01a5e15fb5 100644 --- a/vhdlpp/entity.h +++ b/vhdlpp/entity.h @@ -45,6 +45,10 @@ class InterfacePort : public LineInfo { : mode(PORT_NONE), type(typ), expr(NULL) {} + InterfacePort(const VType*typ, port_mode_t mod) + : mode(mod), type(typ), expr(NULL) + {} + // Port direction from the source code. port_mode_t mode; // Name of the port from the source code diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index ee609ae60d..50c2e8e2c5 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -903,4 +903,8 @@ class ExpTime : public Expression { timeunit_t unit_; }; +// 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); + #endif /* IVL_expression_H */ diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 0c57544b36..79fa6c04c2 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -782,14 +782,8 @@ int ExpFunc::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) def_ = prog; // Elaborate arguments - for (size_t idx = 0 ; idx < argv_.size() ; idx += 1) { - const VType*tmp = argv_[idx]->probe_type(ent, scope); - const VType*param_type = prog ? prog->peek_param_type(idx) : NULL; - - if(!tmp && param_type) - tmp = param_type; - - errors += argv_[idx]->elaborate_expr(ent, scope, tmp); + for (size_t idx = 0; idx < argv_.size(); ++idx) { + errors += elaborate_argument(argv_[idx], prog, idx, ent, scope); } // SystemVerilog functions work only with defined size data types, therefore @@ -1058,3 +1052,28 @@ int ExpTime::elaborate_expr(Entity*, ScopeBase*, const VType*) set_type(&primitive_INTEGER); return 0; } + +int elaborate_argument(Expression*expr, const SubprogramHeader*subp, + int idx, Entity*ent, ScopeBase*scope) +{ + const VType*type = expr->probe_type(ent, scope); + + if(subp) { + const InterfacePort*param = subp->peek_param(idx); + + // Enable reg_flag for variables that might be modified in subprograms + if(param->mode == PORT_OUT || param->mode == PORT_INOUT) { + if(const ExpName*e = dynamic_cast(expr)) { + if(Signal*sig = scope->find_signal(e->peek_name())) + sig->count_ref_sequ(); + else if(Variable*var = scope->find_variable(e->peek_name())) + var->count_ref_sequ(); + } + } + + if(!type) + type = param->type; + } + + return expr->elaborate_expr(ent, scope, type); +} diff --git a/vhdlpp/sequential_elaborate.cc b/vhdlpp/sequential_elaborate.cc index 6967fc574d..3f90f0f9f1 100644 --- a/vhdlpp/sequential_elaborate.cc +++ b/vhdlpp/sequential_elaborate.cc @@ -173,13 +173,8 @@ int ProcedureCall::elaborate(Entity*ent, ScopeBase*scope) if(param_list_) { for(list::iterator cur = param_list_->begin() ; cur != param_list_->end() ; ++cur) { - const VType*tmp = (*cur)->expr()->probe_type(ent, scope); - const VType*param_type = def_ ? def_->peek_param_type(idx) : NULL; - - if(!tmp && param_type) - tmp = param_type; - - errors += (*cur)->expr()->elaborate_expr(ent, scope, tmp); + errors += elaborate_argument((*cur)->expr(), def_, idx, ent, scope); + ++idx; } } diff --git a/vhdlpp/subprogram.cc b/vhdlpp/subprogram.cc index 9f6c58aeeb..59862f97d1 100644 --- a/vhdlpp/subprogram.cc +++ b/vhdlpp/subprogram.cc @@ -138,7 +138,7 @@ const InterfacePort*SubprogramHeader::find_param(perm_string nam) const return NULL; } -const VType*SubprogramHeader::peek_param_type(int idx) const +const InterfacePort*SubprogramHeader::peek_param(int idx) const { if(!ports_ || idx < 0 || (size_t)idx >= ports_->size()) return NULL; @@ -146,7 +146,17 @@ const VType*SubprogramHeader::peek_param_type(int idx) const std::list::const_iterator p = ports_->begin(); std::advance(p, idx); - return (*p)->type; + return *p; +} + +const VType*SubprogramHeader::peek_param_type(int idx) const +{ + const InterfacePort*port = peek_param(idx); + + if(port) + return port->type; + + return NULL; } void SubprogramHeader::set_parent(const ScopeBase*par) diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h index 0aa5dbdbc3..6972ae0be2 100644 --- a/vhdlpp/subprogram.h +++ b/vhdlpp/subprogram.h @@ -71,6 +71,7 @@ class SubprogramHeader : public LineInfo { bool compare_specification(SubprogramHeader*that) const; const InterfacePort*find_param(perm_string nam) const; + const InterfacePort*peek_param(int idx) const; const VType*peek_param_type(int idx) const; const VType*peek_return_type() const { return return_type_; } From 7b483e69d842aea1bf89ea5f0813aedfda6a5e55 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 23 Sep 2015 11:53:00 +0200 Subject: [PATCH 10/24] vhdlpp: Minor changes. --- vhdlpp/std_funcs.cc | 3 ++- vhdlpp/std_types.cc | 6 +++--- vhdlpp/std_types.h | 1 - vhdlpp/subprogram_emit.cc | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/vhdlpp/std_funcs.cc b/vhdlpp/std_funcs.cc index 7d7a5ab917..b75aa1ae04 100644 --- a/vhdlpp/std_funcs.cc +++ b/vhdlpp/std_funcs.cc @@ -141,7 +141,8 @@ void preload_std_funcs(void) fn_resize = new SubprogramSizeCast(perm_string::literal("resize")); std_subprograms[fn_resize->name()] = fn_resize; - /* function conv_std_logic_vector + /* std_logic_arith library + * function conv_std_logic_vector(arg: integer; size: integer) return std_logic_vector; */ fn_conv_std_logic_vector = new SubprogramSizeCast(perm_string::literal("conv_std_logic_vector")); std_subprograms[fn_conv_std_logic_vector->name()] = fn_conv_std_logic_vector; diff --git a/vhdlpp/std_types.cc b/vhdlpp/std_types.cc index 311c74f1e4..0454a65e0d 100644 --- a/vhdlpp/std_types.cc +++ b/vhdlpp/std_types.cc @@ -21,9 +21,9 @@ #include "std_types.h" #include "scope.h" -static std::map std_types; +static map std_types; // this list contains enums used by typedefs in the std_types map -static std::list std_enums; +static list std_enums; const VTypePrimitive primitive_BIT(VTypePrimitive::BIT, true); const VTypePrimitive primitive_INTEGER(VTypePrimitive::INTEGER); @@ -45,7 +45,7 @@ const VTypeArray primitive_UNSIGNED(&primitive_STDLOGIC, vector*enum_BOOLEAN_vals = new std::list; + list*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); diff --git a/vhdlpp/std_types.h b/vhdlpp/std_types.h index 72bfa20759..80aef1e17c 100644 --- a/vhdlpp/std_types.h +++ b/vhdlpp/std_types.h @@ -29,7 +29,6 @@ bool is_global_type(perm_string type_name); void delete_global_types(); const VTypeEnum*find_std_enum_name(perm_string name); -extern const VTypePrimitive primitive_BOOLEAN; extern const VTypePrimitive primitive_BIT; extern const VTypePrimitive primitive_INTEGER; extern const VTypePrimitive primitive_NATURAL; diff --git a/vhdlpp/subprogram_emit.cc b/vhdlpp/subprogram_emit.cc index 6c880e90fe..907550475e 100644 --- a/vhdlpp/subprogram_emit.cc +++ b/vhdlpp/subprogram_emit.cc @@ -31,7 +31,7 @@ int SubprogramBody::emit_package(ostream&fd) const for (map::const_iterator cur = new_variables_.begin() ; cur != new_variables_.end() ; ++cur) { - // Workaround to enable reg_flag for variables + // Enable reg_flag for variables cur->second->count_ref_sequ(); errors += cur->second->emit(fd, NULL, NULL); } From 2f40c965271532b5697f52ed9628511d95360a54 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 23 Sep 2015 16:25:35 +0200 Subject: [PATCH 11/24] vhdlpp: Basic support for std.textio & ieee.std_logic_textio. --- vhdlpp/library.cc | 6 +- vhdlpp/parse.y | 22 ++++++ vhdlpp/std_funcs.cc | 159 ++++++++++++++++++++++++++++++++++++++++++++ vhdlpp/std_types.cc | 11 +++ vhdlpp/std_types.h | 3 + 5 files changed, 199 insertions(+), 2 deletions(-) diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index c6d9d0b319..03f0ff9dfa 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -361,13 +361,15 @@ static void import_ieee_use(ActiveScope*res, perm_string package, perm_string na } } -static void import_std_use(const YYLTYPE&loc, ActiveScope*/*res*/, perm_string package, perm_string name) +static void import_std_use(const YYLTYPE&loc, ActiveScope*res, perm_string package, perm_string name) { if (package == "standard") { // do nothing return; } else if (package == "textio") { - cerr << "warning: textio package not really supported" << endl; + res->use_name(perm_string::literal("text"), &primitive_INTEGER); + res->use_name(perm_string::literal("line"), &primitive_STRING); + res->use_name(type_FILE_OPEN_KIND.peek_name(), &type_FILE_OPEN_KIND); return; } else { sorrymsg(loc, "package %s of library %s not yet supported", package.str(), name.str()); diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 90e62f23b9..6a210f0577 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -1235,6 +1235,26 @@ factor } ; +file_declaration + : K_file identifier_list ':' IDENTIFIER ';' + { + if (strcasecmp($4, "TEXT")) + errormsg(@1, "file declaration expected TEXT type\n"); + + for (std::list::iterator cur = $2->begin() + ; cur != $2->end() ; ++cur) { + Variable*var = new Variable(*cur, &primitive_INTEGER); + FILE_NAME(var, @1); + active_scope->bind_name(*cur, var); + } + delete $2; + } + | K_file error ';' + { errormsg(@2, "Syntax error in file declaration.\n"); + yyerrok; + } + ; + for_generate_statement : IDENTIFIER ':' K_for IDENTIFIER K_in range K_generate generate_statement_body @@ -1961,6 +1981,7 @@ procedure_specification /* IEEE 1076-2008 P4.2.1 */ process_declarative_item : variable_declaration + | file_declaration ; process_declarative_part @@ -2506,6 +2527,7 @@ subprogram_declaration subprogram_declarative_item /* IEEE 1079-2008 P4.3 */ : variable_declaration + | file_declaration ; subprogram_declarative_item_list diff --git a/vhdlpp/std_funcs.cc b/vhdlpp/std_funcs.cc index b75aa1ae04..5b875d98f4 100644 --- a/vhdlpp/std_funcs.cc +++ b/vhdlpp/std_funcs.cc @@ -92,6 +92,78 @@ static class SubprogramSizeCast : public SubprogramHeader { } }*fn_conv_std_logic_vector, *fn_resize; +static class SubprogramReadWrite : public SubprogramBuiltin { + public: + SubprogramReadWrite(perm_string nam, perm_string newnam) + : SubprogramBuiltin(nam, newnam, NULL, NULL) { + ports_ = new std::list(); + ports_->push_back(new InterfacePort(&primitive_STRING, PORT_INOUT)); + ports_->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR, PORT_INOUT)); + ports_->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); + } + + bool is_std() const { return true; } + + // Format types handled by $ivlh_read/write (see vpi/vhdl_textio.c) + enum format_t { FORMAT_STD, FORMAT_BOOL, FORMAT_TIME, FORMAT_HEX, FORMAT_STRING }; + + int emit_args(const std::vector&argv, + std::ostream&out, Entity*ent, ScopeBase*scope) const { + + int errors = 0; + + for(int i = 0; i < 2; ++i) { + errors += argv[i]->emit(out, ent, scope); + out << ", "; + } + + const VType*arg_type = argv[1]->probe_type(ent, scope); + const VTypeArray*arr = dynamic_cast(arg_type); + const VTypePrimitive*prim = dynamic_cast(arg_type); + + // Pick the right format + if(prim && prim->type() == VTypePrimitive::TIME) + out << FORMAT_TIME; + else if(arg_type && arg_type->type_match(&type_BOOLEAN)) + out << FORMAT_BOOL; + else if((arg_type && arg_type->type_match(&primitive_CHARACTER)) || + (arr && arr->element_type() == &primitive_CHARACTER)) + out << FORMAT_STRING; + else + out << FORMAT_STD; + + return errors; + } +}*fn_read, *fn_write; + +static class SubprogramHexReadWrite : public SubprogramBuiltin { + public: + SubprogramHexReadWrite(perm_string nam, perm_string newnam) + : SubprogramBuiltin(nam, newnam, NULL, NULL) { + ports_ = new std::list(); + ports_->push_back(new InterfacePort(&primitive_STRING, PORT_INOUT)); + ports_->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR, PORT_INOUT)); + ports_->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); + } + + bool is_std() const { return true; } + + int emit_args(const std::vector&argv, + std::ostream&out, Entity*ent, ScopeBase*scope) const { + + int errors = 0; + + for(int i = 0; i < 2; ++i) { + errors += argv[i]->emit(out, ent, scope); + out << ", "; + } + + out << SubprogramReadWrite::FORMAT_HEX; + + return errors; + } +}*fn_hread, *fn_hwrite; + static SubprogramBuiltin*fn_std_logic_vector; static SubprogramBuiltin*fn_to_unsigned; static SubprogramBuiltin*fn_unsigned; @@ -103,6 +175,13 @@ static SubprogramBuiltin*fn_falling_edge; static SubprogramBuiltin*fn_and_reduce; static SubprogramBuiltin*fn_or_reduce; +static SubprogramBuiltin*fn_file_open; +static SubprogramBuiltin*fn_file_close; +static SubprogramBuiltin*fn_endfile; + +static SubprogramBuiltin*fn_readline; +static SubprogramBuiltin*fn_writeline; + void preload_std_funcs(void) { /* numeric_std library @@ -207,6 +286,86 @@ void preload_std_funcs(void) perm_string::literal("$ivlh_to_unsigned"), fn_to_unsigned_args, &primitive_UNSIGNED); std_subprograms[fn_to_unsigned->name()] = fn_to_unsigned; + + /* procedure file_open (file f: text; filename: in string, file_open_kind: in mode); + */ + std::list*fn_file_open_args = new std::list(); + fn_file_open_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); + fn_file_open_args->push_back(new InterfacePort(&primitive_STRING, PORT_IN)); + fn_file_open_args->push_back(new InterfacePort(&type_FILE_OPEN_KIND, PORT_IN)); + fn_file_open = new SubprogramBuiltin(perm_string::literal("file_open"), + perm_string::literal("$ivlh_file_open"), + fn_file_open_args, NULL); + std_subprograms[fn_file_open->name()] = fn_file_open; + + /* std.textio library + * procedure file_close (file f: text); + */ + std::list*fn_file_close_args = new std::list(); + fn_file_close_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); + fn_file_close = new SubprogramBuiltin(perm_string::literal("file_close"), + perm_string::literal("$fclose"), + fn_file_close_args, NULL); + std_subprograms[fn_file_close->name()] = fn_file_close; + + /* std.textio library + * procedure read (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time); + */ + fn_read = new SubprogramReadWrite(perm_string::literal("read"), + perm_string::literal("$ivlh_read")); + std_subprograms[fn_read->name()] = fn_read; + + /* std.textio library + * procedure write (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time); + */ + fn_write = new SubprogramReadWrite(perm_string::literal("write"), + perm_string::literal("$ivlh_write")); + std_subprograms[fn_write->name()] = fn_write; + + /* std.textio library + * procedure hread (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time); + */ + fn_hread = new SubprogramHexReadWrite(perm_string::literal("hread"), + perm_string::literal("$ivlh_read")); + std_subprograms[fn_hread->name()] = fn_hread; + + /* std.textio library + * procedure hwrite (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time); + */ + fn_hwrite = new SubprogramHexReadWrite(perm_string::literal("hwrite"), + perm_string::literal("$ivlh_write")); + std_subprograms[fn_hwrite->name()] = fn_hwrite; + + /* std.textio library + * procedure readline (file f: text; l: inout line); + */ + std::list*fn_readline_args = new std::list(); + fn_readline_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); + fn_readline_args->push_back(new InterfacePort(&primitive_STRING, PORT_OUT)); + fn_readline = new SubprogramBuiltin(perm_string::literal("readline"), + perm_string::literal("$ivlh_readline"), + fn_readline_args, NULL); + std_subprograms[fn_readline->name()] = fn_readline; + + /* std.textio library + * procedure writeline (file f: text; l: inout line); + */ + std::list*fn_writeline_args = new std::list(); + fn_writeline_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); + fn_writeline_args->push_back(new InterfacePort(&primitive_STRING, PORT_IN)); + fn_writeline = new SubprogramBuiltin(perm_string::literal("writeline"), + perm_string::literal("$ivlh_writeline"), + fn_writeline_args, NULL); + std_subprograms[fn_writeline->name()] = fn_writeline; + + /* function endline (file f: text) return boolean; + */ + std::list*fn_endfile_args = new std::list(); + fn_endfile_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); + fn_endfile = new SubprogramBuiltin(perm_string::literal("endfile"), + perm_string::literal("$feof"), + fn_endfile_args, &type_BOOLEAN); + std_subprograms[fn_endfile->name()] = fn_endfile; } void delete_std_funcs() diff --git a/vhdlpp/std_types.cc b/vhdlpp/std_types.cc index 0454a65e0d..516b6ac17d 100644 --- a/vhdlpp/std_types.cc +++ b/vhdlpp/std_types.cc @@ -33,6 +33,7 @@ const VTypePrimitive primitive_STDLOGIC(VTypePrimitive::STDLOGIC, true); const VTypePrimitive primitive_TIME(VTypePrimitive::TIME); VTypeDef type_BOOLEAN(perm_string::literal("boolean")); +VTypeDef type_FILE_OPEN_KIND(perm_string::literal("file_open_kind")); const VTypeArray primitive_CHARACTER(&primitive_BIT, 7, 0); const VTypeArray primitive_BIT_VECTOR(&primitive_BIT, vector (1)); @@ -53,6 +54,16 @@ void generate_global_types(ActiveScope*res) 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); + 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); + res->use_name(type_BOOLEAN.peek_name(), &type_BOOLEAN); res->use_name(perm_string::literal("bit"), &primitive_BIT); res->use_name(perm_string::literal("bit_vector"), &primitive_BIT_VECTOR); diff --git a/vhdlpp/std_types.h b/vhdlpp/std_types.h index 80aef1e17c..033ac21674 100644 --- a/vhdlpp/std_types.h +++ b/vhdlpp/std_types.h @@ -35,8 +35,11 @@ extern const VTypePrimitive primitive_NATURAL; extern const VTypePrimitive primitive_REAL; extern const VTypePrimitive primitive_STDLOGIC; extern const VTypePrimitive primitive_TIME; +extern const VTypePrimitive primitive_TEXT; +extern const VTypePrimitive primitive_LINE; extern VTypeDef type_BOOLEAN; +extern VTypeDef type_FILE_OPEN_KIND; extern const VTypeArray primitive_CHARACTER; extern const VTypeArray primitive_BIT_VECTOR; From 5535b7d26c93ec4351a2826094c5b6ce2e0e6f38 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 24 Nov 2015 15:29:18 +0100 Subject: [PATCH 12/24] vhdlpp: Corrected error messages. --- vhdlpp/parse.y | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 6a210f0577..e5069a2cea 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -1239,7 +1239,7 @@ file_declaration : K_file identifier_list ':' IDENTIFIER ';' { if (strcasecmp($4, "TEXT")) - errormsg(@1, "file declaration expected TEXT type\n"); + sorrymsg(@1, "file declaration currently handles only TEXT type.\n"); for (std::list::iterator cur = $2->begin() ; cur != $2->end() ; ++cur) { @@ -1893,10 +1893,10 @@ primary else if(!strcasecmp($2, "fs")) unit = ExpTime::FS; else - errormsg(@2, "Invalid time unit (accepted are fs, ps, ns, us, ms, s)."); + errormsg(@2, "Invalid time unit (accepted are fs, ps, ns, us, ms, s).\n"); if($1 < 0) - errormsg(@1, "Time cannot be negative."); + errormsg(@1, "Time cannot be negative.\n"); ExpTime*tmp = new ExpTime($1, unit); FILE_NAME(tmp, @1); From cb40a845e1c5fac7449dff6b5cb7c5e9c1aa13a0 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 24 Nov 2015 16:52:32 +0100 Subject: [PATCH 13/24] vhdlpp: Allow procedure calls with empty param list. --- vhdlpp/sequential_emit.cc | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index ec60fa3940..f762288fd3 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -210,12 +210,15 @@ void VariableSeqAssignment::write_to_stream(ostream&fd) int ProcedureCall::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; + std::vectorparams; - std::vectorparams(param_list_->size()); - int i = 0; - for(std::list::iterator it = param_list_->begin(); - it != param_list_->end(); ++it) - params[i++] = (*it)->expr(); + if(param_list_) { + params.reserve(param_list_->size()); + + for(std::list::iterator it = param_list_->begin(); + it != param_list_->end(); ++it) + params.push_back((*it)->expr()); + } const Package*pkg = dynamic_cast (def_->get_parent()); if (pkg != 0) From e4ba4b5acd492920f936af509bd30560bd2edb3c Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 25 Nov 2015 18:15:09 +0100 Subject: [PATCH 14/24] vhdlpp: Added means to use 'initial' and 'final' blocks during translation. --- vhdlpp/architec.cc | 22 +++++++++++++--- vhdlpp/architec.h | 49 ++++++++++++++++++++++++++++++------ vhdlpp/architec_debug.cc | 31 ++++++++++++++++++----- vhdlpp/architec_elaborate.cc | 28 +++++++++++++-------- vhdlpp/architec_emit.cc | 37 ++++++++++++++++++++++----- 5 files changed, 134 insertions(+), 33 deletions(-) diff --git a/vhdlpp/architec.cc b/vhdlpp/architec.cc index b576af3b78..57b885feb4 100644 --- a/vhdlpp/architec.cc +++ b/vhdlpp/architec.cc @@ -20,6 +20,7 @@ # include "architec.h" # include "expression.h" # include "parse_types.h" +# include "sequential.h" // Need this for parse_errors? # include "parse_api.h" # include @@ -229,18 +230,33 @@ Expression*ComponentInstantiation::find_generic_map(perm_string by_name) const return p->second; } +StatementList::StatementList(std::list*statement_list) +{ + if(statement_list) + statements_.splice(statements_.end(), *statement_list); +} + +StatementList::~StatementList() +{ + for(std::list::iterator it = statements_.begin(); + it != statements_.end(); ++it) { + delete *it; + } +} ProcessStatement::ProcessStatement(perm_string iname, std::list*sensitivity_list, std::list*statements_list) -: iname_(iname) +: StatementList(statements_list), iname_(iname) { if (sensitivity_list) sensitivity_list_.splice(sensitivity_list_.end(), *sensitivity_list); - if (statements_list) - statements_list_.splice(statements_list_.end(), *statements_list); } ProcessStatement::~ProcessStatement() { + for(std::list::iterator it = sensitivity_list_.begin(); + it != sensitivity_list_.end(); ++it) { + delete *it; + } } diff --git a/vhdlpp/architec.h b/vhdlpp/architec.h index 869e89d196..435ad36399 100644 --- a/vhdlpp/architec.h +++ b/vhdlpp/architec.h @@ -215,7 +215,44 @@ class ComponentInstantiation : public Architecture::Statement { std::map port_map_; }; -class ProcessStatement : public Architecture::Statement { +class StatementList : public Architecture::Statement { + public: + StatementList(std::list*statement_list); + virtual ~StatementList(); + + virtual int elaborate(Entity*ent, Architecture*arc); + virtual int emit(ostream&out, Entity*entity, Architecture*arc); + virtual void dump(ostream&out, int indent =0) const; + + std::list& stmt_list() { return statements_; } + + private: + std::list statements_; +}; + +// There is no direct VHDL countepart to SV 'initial' statement, +// but we can still use it during the translation process. +class InitialStatement : public StatementList { + public: + InitialStatement(std::list*statement_list) + : StatementList(statement_list) {} + + int emit(ostream&out, Entity*entity, Architecture*arc); + void dump(ostream&out, int indent =0) const; +}; + +// There is no direct VHDL countepart to SV 'final' statement, +// but we can still use it during the translation process. +class FinalStatement : public StatementList { + public: + FinalStatement(std::list*statement_list) + : StatementList(statement_list) {} + + int emit(ostream&out, Entity*entity, Architecture*arc); + void dump(ostream&out, int indent =0) const; +}; + +class ProcessStatement : public StatementList { public: ProcessStatement(perm_string iname, @@ -223,20 +260,16 @@ class ProcessStatement : public Architecture::Statement { std::list*statement_list); ~ProcessStatement(); - virtual int elaborate(Entity*ent, Architecture*arc); - virtual int emit(ostream&out, Entity*entity, Architecture*arc); - virtual void dump(ostream&out, int indent =0) const; + int elaborate(Entity*ent, Architecture*arc); + int emit(ostream&out, Entity*entity, Architecture*arc); + void dump(ostream&out, int indent =0) const; private: int rewrite_as_always_edge_(Entity*ent, Architecture*arc); int extract_anyedge_(Entity*ent, Architecture*arc); - private: perm_string iname_; - std::list sensitivity_list_; - std::list statements_list_; - }; #endif /* IVL_architec_H */ diff --git a/vhdlpp/architec_debug.cc b/vhdlpp/architec_debug.cc index d60bf48fb8..630da357c9 100644 --- a/vhdlpp/architec_debug.cc +++ b/vhdlpp/architec_debug.cc @@ -95,6 +95,30 @@ void SignalAssignment::dump(ostream&out, int indent) const } } +void StatementList::dump(ostream&out, int indent) const +{ + out << setw(indent+3) << "" << "sequence of statements:" << endl; + + for (list::const_iterator cur = statements_.begin() + ; cur != statements_.end() ; ++cur) { + (*cur)->dump(out, indent+4); + } +} + +void InitialStatement::dump(ostream&out, int indent) const +{ + out << setw(indent) << "" << "InitialStatement file=" << get_fileline() << endl; + + StatementList::dump(out, indent); +} + +void FinalStatement::dump(ostream&out, int indent) const +{ + out << setw(indent) << "" << "FinalStatment file=" << get_fileline() << endl; + + StatementList::dump(out, indent); +} + void ProcessStatement::dump(ostream&out, int indent) const { out << setw(indent) << "" << "ProcessStatement name_=" << iname_ @@ -107,10 +131,5 @@ void ProcessStatement::dump(ostream&out, int indent) const (*cur)->dump(out, indent+4); } - out << setw(indent+3) << "" << "sequence of statements:" << endl; - - for (list::const_iterator cur = statements_list_.begin() - ; cur != statements_list_.end() ; ++cur) { - (*cur)->dump(out, indent+4); - } + StatementList::dump(out, indent); } diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index e734ce1fc0..eba3ec49eb 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -179,11 +179,11 @@ int ProcessStatement::rewrite_as_always_edge_(Entity*, Architecture*) return -1; // If there are multiple statements, I give up. - if (statements_list_.size() != 1) + if (stmt_list().size() != 1) return -1; Expression*se = sensitivity_list_.front(); - SequentialStmt*stmt_raw = statements_list_.front(); + SequentialStmt*stmt_raw = stmt_list().front(); // If the statement is not an if-statement, I give up. IfSequential*stmt = dynamic_cast (stmt_raw); @@ -258,22 +258,33 @@ int ProcessStatement::rewrite_as_always_edge_(Entity*, Architecture*) // Replace the statement with the body of the always // statement, which is the true clause of the top "if" // statement. There should be no "else" clause. - assert(statements_list_.size() == 1); - statements_list_.pop_front(); + assert(stmt_list().size() == 1); + stmt_list().pop_front(); - stmt->extract_true(statements_list_); + stmt->extract_true(stmt_list()); delete stmt; return 0; } +int StatementList::elaborate(Entity*ent, Architecture*arc) +{ + int errors = 0; + + for (std::list::iterator it = statements_.begin(); + it != statements_.end(); ++it) { + errors += (*it)->elaborate(ent, arc); + } + + return errors; +} + /* * Change the "process () " into "always @() ..." */ int ProcessStatement::extract_anyedge_(Entity*, Architecture*) { - vector se; while (! sensitivity_list_.empty()) { se.push_back(sensitivity_list_.front()); @@ -297,10 +308,7 @@ int ProcessStatement::elaborate(Entity*ent, Architecture*arc) extract_anyedge_(ent, arc); } - for (list::iterator cur = statements_list_.begin() - ; cur != statements_list_.end() ; ++cur) { - errors += (*cur)->elaborate(ent, arc); - } + StatementList::elaborate(ent, arc); return errors; } diff --git a/vhdlpp/architec_emit.cc b/vhdlpp/architec_emit.cc index 7164f5fad7..e041d99cda 100644 --- a/vhdlpp/architec_emit.cc +++ b/vhdlpp/architec_emit.cc @@ -246,6 +246,36 @@ int IfGenerate::emit(ostream&out, Entity*ent, Architecture*arc) return errors; } +int StatementList::emit(ostream&out, Entity*ent, Architecture*arc) +{ + int errors = 0; + + for (std::list::iterator it = statements_.begin(); + it != statements_.end(); ++it) { + errors += (*it)->emit(out, ent, arc); + } + + return errors; +} + +int InitialStatement::emit(ostream&out, Entity*ent, Architecture*arc) +{ + out << "initial begin" << endl; + int errors = StatementList::emit(out, ent, arc); + out << "end" << endl; + + return errors; +} + +int FinalStatement::emit(ostream&out, Entity*ent, Architecture*arc) +{ + out << "final begin" << endl; + int errors = StatementList::emit(out, ent, arc); + out << "end" << endl; + + return errors; +} + /* * Emit a process statement using "always" syntax. * @@ -256,14 +286,9 @@ int IfGenerate::emit(ostream&out, Entity*ent, Architecture*arc) */ int ProcessStatement::emit(ostream&out, Entity*ent, Architecture*arc) { - int errors = 0; - out << "always begin" << endl; - for (list::iterator cur = statements_list_.begin() - ; cur != statements_list_.end() ; ++cur) { - errors += (*cur)->emit(out, ent, arc); - } + int errors = StatementList::emit(out, ent, arc); if (! sensitivity_list_.empty()) { out << "@("; From 83f01a5fc4a6c82103ae98294fd7f81b6de0e600 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 30 Nov 2015 17:08:02 +0100 Subject: [PATCH 15/24] vhdlpp: Support for implicit initalizers and finalizers. --- vhdlpp/architec_elaborate.cc | 8 ++++++++ vhdlpp/scope.cc | 3 +++ vhdlpp/scope.h | 21 +++++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index eba3ec49eb..7430bae83a 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -59,6 +59,14 @@ int Architecture::elaborate(Entity*entity) cur->second->elaborate_init_expr(entity, this); } + // Create 'initial' and 'final' blocks for implicit + // initalization and clean-up actions + if(!initializers_.empty()) + statements_.push_front(new InitialStatement(&initializers_)); + + if(!finalizers_.empty()) + statements_.push_front(new FinalStatement(&finalizers_)); + for (list::iterator cur = statements_.begin() ; cur != statements_.end() ; ++cur) { diff --git a/vhdlpp/scope.cc b/vhdlpp/scope.cc index b178547c7c..bc1e429790 100644 --- a/vhdlpp/scope.cc +++ b/vhdlpp/scope.cc @@ -63,6 +63,9 @@ ScopeBase::ScopeBase(const ActiveScope&ref) use_enums_ = ref.use_enums_; + initializers_ = ref.initializers_; + finalizers_ = ref.finalizers_; + // This constructor is invoked when the parser is finished with // an active scope and is making the actual scope. At this point // we know that "this" is the parent scope for the subprograms, diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index f7742e7168..444583d097 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -34,6 +34,7 @@ class ComponentBase; class Package; class SubprogramHeader; class VType; +class SequentialStmt; template struct delete_object{ @@ -75,6 +76,20 @@ class ScopeBase { cur_subprograms_[name] = obj; } + // Adds a statement to implicit initializers list + // (emitted in a 'initial block). + void add_initializer(SequentialStmt* s) + { + initializers_.push_back(s); + } + + // Adds a statement to implicit finalizers list + // (emitted in a 'final' block). + void add_finalizer(SequentialStmt* s) + { + finalizers_.push_back(s); + } + protected: void cleanup(); @@ -122,6 +137,12 @@ class ScopeBase { std::list use_enums_; + // List of statements that should be emitted in a 'initial' block + std::list initializers_; + + // List of statements that should be emitted in a 'final' block + std::list finalizers_; + void do_use_from(const ScopeBase*that); }; From d5853ff5d7fdf25531995924d857b69629b7716e Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 30 Nov 2015 17:13:06 +0100 Subject: [PATCH 16/24] vhdlpp: File declarations with specified file name and open mode. --- vhdlpp/parse.y | 43 ++++++++++++++++++++++++++++++++++++++++++- vhdlpp/parse_types.h | 19 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index e5069a2cea..e326658cf3 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -266,6 +266,8 @@ static void touchup_interface_for_functions(std::list*ports) ReportStmt::severity_t severity; SubprogramHeader*subprogram; + + file_open_info_t*file_info; }; /* The keywords are all tokens. */ @@ -343,6 +345,8 @@ static void touchup_interface_for_functions(std::list*ports) %type process_sensitivity_list process_sensitivity_list_opt %type selected_names use_clause +%type file_open_information file_open_information_opt + %type association_element %type association_list port_map_aspect port_map_aspect_opt %type generic_map_aspect generic_map_aspect_opt @@ -1236,7 +1240,7 @@ factor ; file_declaration - : K_file identifier_list ':' IDENTIFIER ';' + : K_file identifier_list ':' IDENTIFIER file_open_information_opt ';' { if (strcasecmp($4, "TEXT")) sorrymsg(@1, "file declaration currently handles only TEXT type.\n"); @@ -1246,7 +1250,27 @@ file_declaration Variable*var = new Variable(*cur, &primitive_INTEGER); FILE_NAME(var, @1); active_scope->bind_name(*cur, var); + + // there was a file name specified, so it needs an implicit call + // to open it at the beginning of simulation and close it at the end + if($5) { + std::list params; + + // add file_open() call in 'initial' block + params.push_back(new ExpName(*cur)); + params.push_back($5->filename()); + params.push_back($5->kind()); + ProcedureCall*fopen_call = new ProcedureCall(perm_string::literal("file_open"), ¶ms); + active_scope->add_initializer(fopen_call); + + // add file_close() call in 'final' block + params.clear(); + params.push_back(new ExpName(*cur)); + ProcedureCall*fclose_call = new ProcedureCall(perm_string::literal("file_close"), ¶ms); + active_scope->add_finalizer(fclose_call); + } } + delete $2; } | K_file error ';' @@ -1255,6 +1279,23 @@ file_declaration } ; +file_open_information + : K_open IDENTIFIER K_is STRING_LITERAL + { + ExpName*mode = new ExpName(lex_strings.make($2)); + delete[]$2; + $$ = new file_open_info_t(new ExpString($4), mode); + } + | K_is STRING_LITERAL + { + $$ = new file_open_info_t(new ExpString($2)); + } + +file_open_information_opt + : file_open_information { $$ = $1; } + | { $$ = 0; } + ; + for_generate_statement : IDENTIFIER ':' K_for IDENTIFIER K_in range K_generate generate_statement_body diff --git a/vhdlpp/parse_types.h b/vhdlpp/parse_types.h index 3639a9c1ff..838381efe0 100644 --- a/vhdlpp/parse_types.h +++ b/vhdlpp/parse_types.h @@ -102,4 +102,23 @@ struct adding_term { Expression*term; }; +// Stores information for file declarations containing a file name and open mode +// (VHDL-2008 6.4.2.5) +class file_open_info_t { + public: + file_open_info_t(ExpString*filename, ExpName*kind = NULL) + : kind_(kind), filename_(filename) { + // By default files are opened in read-only mode + if(!kind_) kind_ = new ExpName(perm_string::literal("read_mode")); + } + ~file_open_info_t() { delete kind_; delete filename_; } + + ExpName*kind() { return kind_; } + ExpString*filename() { return filename_; } + + private: + ExpName*kind_; + ExpString*filename_; +}; + #endif /* IVL_parse_types_H */ From bb695c6e11ea8625f17215375dc63228943139f6 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 30 Nov 2015 18:08:40 +0100 Subject: [PATCH 17/24] vhdlpp: Fixed infinite recursion when evaluating ExpTime. --- vhdlpp/expression_evaluate.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vhdlpp/expression_evaluate.cc b/vhdlpp/expression_evaluate.cc index 7aa9218580..77ceeff525 100644 --- a/vhdlpp/expression_evaluate.cc +++ b/vhdlpp/expression_evaluate.cc @@ -268,5 +268,5 @@ bool ExpTime::evaluate(ScopeBase*, int64_t&val) const bool ExpTime::evaluate(Entity*, ScopeBase*, int64_t&val) const { - return evaluate(NULL, NULL, val); + return evaluate(NULL, val); } From 9df470c34156e43f4cb036cd3d4c7ccd169bbf98 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 3 Dec 2015 17:53:13 +0100 Subject: [PATCH 18/24] vhdlpp: While loops. --- vhdlpp/parse.y | 8 +------- vhdlpp/sequential.cc | 2 +- vhdlpp/sequential.h | 6 ++++-- vhdlpp/sequential_elaborate.cc | 9 ++++++--- vhdlpp/sequential_emit.cc | 22 ++++++++++++++++++++++ 5 files changed, 34 insertions(+), 13 deletions(-) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index e326658cf3..fa5deded7d 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -1614,14 +1614,8 @@ loop_statement if($1) delete[]$1; if($8) delete[]$8; - ExpLogical* cond = dynamic_cast($3); - if(!cond) { - errormsg(@3, "Iteration condition is not a correct logical expression.\n"); - } - WhileLoopStatement* tmp = new WhileLoopStatement(loop_name, cond, $5); + WhileLoopStatement* tmp = new WhileLoopStatement(loop_name, $3, $5); FILE_NAME(tmp, @1); - - sorrymsg(@1, "Loop statements are not supported.\n"); $$ = tmp; } diff --git a/vhdlpp/sequential.cc b/vhdlpp/sequential.cc index a0f2878cb0..042850426a 100644 --- a/vhdlpp/sequential.cc +++ b/vhdlpp/sequential.cc @@ -259,7 +259,7 @@ VariableSeqAssignment::~VariableSeqAssignment() delete rval_; } -WhileLoopStatement::WhileLoopStatement(perm_string lname, ExpLogical* cond, list* stmts) +WhileLoopStatement::WhileLoopStatement(perm_string lname, Expression* cond, list* stmts) : LoopStatement(lname, stmts), cond_(cond) { } diff --git a/vhdlpp/sequential.h b/vhdlpp/sequential.h index 4ee14cdb59..89bd38bfdb 100644 --- a/vhdlpp/sequential.h +++ b/vhdlpp/sequential.h @@ -235,14 +235,16 @@ class VariableSeqAssignment : public SequentialStmt { class WhileLoopStatement : public LoopStatement { public: WhileLoopStatement(perm_string loop_name, - ExpLogical*, list*); + Expression*, list*); ~WhileLoopStatement(); int elaborate(Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope); + void write_to_stream(std::ostream&fd); void dump(ostream&out, int indent) const; private: - ExpLogical* cond_; + Expression* cond_; }; class ForLoopStatement : public LoopStatement { diff --git a/vhdlpp/sequential_elaborate.cc b/vhdlpp/sequential_elaborate.cc index 3f90f0f9f1..4ba864c2b5 100644 --- a/vhdlpp/sequential_elaborate.cc +++ b/vhdlpp/sequential_elaborate.cc @@ -22,6 +22,7 @@ # include "scope.h" # include "library.h" # include "subprogram.h" +# include "std_types.h" int SequentialStmt::elaborate(Entity*, ScopeBase*) { @@ -203,10 +204,12 @@ int VariableSeqAssignment::elaborate(Entity*ent, ScopeBase*scope) return errors; } -int WhileLoopStatement::elaborate(Entity*, ScopeBase*) +int WhileLoopStatement::elaborate(Entity*ent, ScopeBase*scope) { - //TODO:check whether there is any wait statement in the statements (there should be) - return 0; + int errors = 0; + errors += elaborate_substatements(ent, scope); + errors += cond_->elaborate_expr(ent, scope, cond_->probe_type(ent, scope)); + return errors; } int BasicLoopStatement::elaborate(Entity*, ScopeBase*) diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index f762288fd3..9e122b2134 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -355,6 +355,28 @@ void CaseSeqStmt::CaseStmtAlternative::write_to_stream(ostream&fd) } } +int WhileLoopStatement::emit(ostream&out, Entity*ent, ScopeBase*scope) +{ + int errors = 0; + + out << "while("; + errors += cond_->emit(out, ent, scope); + out << ") begin" << endl; + errors += emit_substatements(out, ent, scope); + out << "end" << endl; + + return errors; +} + +void WhileLoopStatement::write_to_stream(ostream&out) +{ + out << "while("; + cond_->write_to_stream(out); + out << ") loop" << endl; + write_to_stream_substatements(out); + out << "end loop;" << endl; +} + int ForLoopStatement::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; From 652fe378b802145fe4e705f47ff6e4ddf83d67d7 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 3 Dec 2015 17:54:22 +0100 Subject: [PATCH 19/24] vhdlpp:: Added ExpUnary::probe_type() function. --- vhdlpp/expression.h | 1 + vhdlpp/expression_elaborate.cc | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index 50c2e8e2c5..595734737f 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -168,6 +168,7 @@ class ExpUnary : public Expression { inline const Expression*peek_operand() const { return operand1_; } const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const; + const VType*probe_type(Entity*ent, ScopeBase*scope) const; int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void visit(ExprVisitor& func); diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 79fa6c04c2..fbe7f0ec2f 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -376,6 +376,11 @@ const VType*ExpUnary::fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*aty return operand1_->fit_type(ent, scope, atype); } +const VType*ExpUnary::probe_type(Entity*ent, ScopeBase*scope) const +{ + return operand1_->probe_type(ent, scope); +} + int ExpUnary::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) { ivl_assert(*this, ltype != 0); From f4238eb5631507ce488a06ae46a59343a9beafb7 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 3 Dec 2015 17:56:41 +0100 Subject: [PATCH 20/24] vhdlpp: Minor code cleaning. --- vhdlpp/expression.h | 2 -- vhdlpp/expression_elaborate.cc | 10 ---------- vhdlpp/sequential.h | 3 ++- 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index 595734737f..d570d3cee7 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -305,7 +305,6 @@ class ExpAggregate : public Expression { Expression*clone() const; - const VType*probe_type(Entity*ent, ScopeBase*scope) const; const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const; int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&fd) const; @@ -731,7 +730,6 @@ class ExpNameALL : public ExpName { ExpNameALL() : ExpName(perm_string()) { } public: - int elaborate_lval(Entity*ent, ScopeBase*scope, bool); const VType* probe_type(Entity*ent, ScopeBase*scope) const; void dump(ostream&out, int indent =0) const; }; diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index fbe7f0ec2f..29a0e60b3b 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -316,11 +316,6 @@ int ExpName::elaborate_rval(Entity*ent, ScopeBase*scope, const InterfacePort*lva return errors; } -int ExpNameALL::elaborate_lval(Entity*ent, ScopeBase*scope, bool is_sequ) -{ - return Expression::elaborate_lval(ent, scope, is_sequ); -} - 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; @@ -388,11 +383,6 @@ int ExpUnary::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) return operand1_->elaborate_expr(ent, scope, ltype); } -const VType*ExpAggregate::probe_type(Entity*ent, ScopeBase*scope) const -{ - return Expression::probe_type(ent, scope); -} - const VType*ExpAggregate::fit_type(Entity*, ScopeBase*, const VTypeArray*host) const { ivl_assert(*this, elements_.size() == 1); diff --git a/vhdlpp/sequential.h b/vhdlpp/sequential.h index 89bd38bfdb..a952981c04 100644 --- a/vhdlpp/sequential.h +++ b/vhdlpp/sequential.h @@ -297,7 +297,8 @@ class ReportStmt : public SequentialStmt { class AssertStmt : public ReportStmt { public: - AssertStmt(Expression*condition, const char*message, ReportStmt::severity_t severity = ReportStmt::ERROR); + AssertStmt(Expression*condition, const char*message, + ReportStmt::severity_t severity = ReportStmt::ERROR); void dump(ostream&out, int indent) const; int elaborate(Entity*ent, ScopeBase*scope); From 2e9c3555cbc845adad75aa5aeadc4d7dd6711fc4 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 3 Dec 2015 17:56:56 +0100 Subject: [PATCH 21/24] vhdlpp: AssertStmt::elaborate() probes the condition type. --- vhdlpp/sequential_elaborate.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vhdlpp/sequential_elaborate.cc b/vhdlpp/sequential_elaborate.cc index 4ba864c2b5..4b033c6e53 100644 --- a/vhdlpp/sequential_elaborate.cc +++ b/vhdlpp/sequential_elaborate.cc @@ -219,7 +219,7 @@ int BasicLoopStatement::elaborate(Entity*, ScopeBase*) int AssertStmt::elaborate(Entity*ent, ScopeBase*scope) { - return cond_->elaborate_expr(ent, scope, 0); + return cond_->elaborate_expr(ent, scope, cond_->probe_type(ent, scope)); } int WaitForStmt::elaborate(Entity*ent, ScopeBase*scope) From 96a0a84e6cd542733a8322b7efc63d97449e5c5d Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 4 Dec 2015 10:29:08 +0100 Subject: [PATCH 22/24] vhdlpp: Fixed the range boundaries order. --- vhdlpp/vtype.cc | 4 ++-- vhdlpp/vtype.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vhdlpp/vtype.cc b/vhdlpp/vtype.cc index 730eb00a91..58e7e9a160 100644 --- a/vhdlpp/vtype.cc +++ b/vhdlpp/vtype.cc @@ -265,8 +265,8 @@ void VTypeArray::evaluate_ranges(ScopeBase*scope) { } } -VTypeRange::VTypeRange(const VType*base, int64_t end_val, int64_t start_val) -: base_(base), end_(end_val), start_(start_val) +VTypeRange::VTypeRange(const VType*base, int64_t start_val, int64_t end_val) +: base_(base), start_(start_val), end_(end_val) { } diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index bf4968b14d..617bd72c47 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -283,7 +283,7 @@ class VTypeRange : public VType { private: const VType*base_; - int64_t end_, start_; + int64_t start_, end_; }; class VTypeEnum : public VType { From 7cebed738258758745e6b04d6d20bae368775d57 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 4 Dec 2015 11:38:19 +0100 Subject: [PATCH 23/24] vhdlpp: Disabled evaluation for ExpTime. It was always evaluated to a value expressed in femtoseconds, which not always might be the case. --- vhdlpp/expression.h | 4 ++-- vhdlpp/expression_evaluate.cc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index d570d3cee7..eb83474df9 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -891,8 +891,8 @@ 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; + //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: diff --git a/vhdlpp/expression_evaluate.cc b/vhdlpp/expression_evaluate.cc index 77ceeff525..0d7ef16349 100644 --- a/vhdlpp/expression_evaluate.cc +++ b/vhdlpp/expression_evaluate.cc @@ -252,7 +252,7 @@ bool ExpShift::evaluate(ScopeBase*scope, int64_t&val) const return true; } -bool ExpTime::evaluate(ScopeBase*, int64_t&val) const +/*bool ExpTime::evaluate(ScopeBase*, int64_t&val) const { double v = to_fs(); @@ -269,4 +269,4 @@ bool ExpTime::evaluate(ScopeBase*, int64_t&val) const bool ExpTime::evaluate(Entity*, ScopeBase*, int64_t&val) const { return evaluate(NULL, val); -} +}*/ From ab025f1e3b0807d8f8dd6365399e9476720c975c Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 4 Dec 2015 11:40:03 +0100 Subject: [PATCH 24/24] vhdlpp: VTypeRange split to VTypeRangeConst and VTypeRangeExpr. When range cannot be evaluated it uses the original expressions. --- vhdlpp/parse_misc.cc | 18 ++++++++--------- vhdlpp/vtype.cc | 26 ++++++++++++++++++++++-- vhdlpp/vtype.h | 45 ++++++++++++++++++++++++++++++++++------- vhdlpp/vtype_stream.cc | 46 ++++++++++++++++++++++++++++++------------ 4 files changed, 103 insertions(+), 32 deletions(-) diff --git a/vhdlpp/parse_misc.cc b/vhdlpp/parse_misc.cc index f49a631c3e..752f7eeb9a 100644 --- a/vhdlpp/parse_misc.cc +++ b/vhdlpp/parse_misc.cc @@ -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*/ , + bool downto, Expression*range_right) { const VType*base_type = parse_type_by_name(lex_strings.make(base_name)); @@ -143,15 +143,13 @@ const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name, assert(range_left && range_right); int64_t left_val, right_val; - bool rc = range_left->evaluate(scope, left_val); - if (rc == false) - return 0; - - rc = range_right->evaluate(scope, right_val); - if (rc == false) - return 0; + VTypeRange*subtype; - VTypeRange*sub_type = new VTypeRange(base_type, left_val, right_val); + 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); + } - return sub_type; + return subtype; } diff --git a/vhdlpp/vtype.cc b/vhdlpp/vtype.cc index 58e7e9a160..6bf8c4eb28 100644 --- a/vhdlpp/vtype.cc +++ b/vhdlpp/vtype.cc @@ -265,8 +265,8 @@ void VTypeArray::evaluate_ranges(ScopeBase*scope) { } } -VTypeRange::VTypeRange(const VType*base, int64_t start_val, int64_t end_val) -: base_(base), start_(start_val), end_(end_val) +VTypeRange::VTypeRange(const VType*base) +: base_(base) { } @@ -274,6 +274,28 @@ VTypeRange::~VTypeRange() { } +VTypeRangeConst::VTypeRangeConst(const VType*base, int64_t start_val, int64_t end_val) +: VTypeRange(base), start_(start_val), end_(end_val) +{ +} + +VTypeRangeExpr::VTypeRangeExpr(const VType*base, Expression*start_expr, + Expression*end_expr, bool downto) +: VTypeRange(base), start_(start_expr), end_(end_expr), downto_(downto) +{ +} + +VTypeRangeExpr::~VTypeRangeExpr() +{ + delete start_; + delete end_; +} + +VType*VTypeRangeExpr::clone() const { + return new VTypeRangeExpr(base_type()->clone(), start_->clone(), + end_->clone(), downto_); +} + VTypeEnum::VTypeEnum(const std::list*names) : names_(names->size()) { diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index 617bd72c47..d97d13a9a3 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -269,21 +269,52 @@ class VTypeArray : public VType { class VTypeRange : public VType { public: - VTypeRange(const VType*base, int64_t end, int64_t start); - ~VTypeRange(); + VTypeRange(const VType*base); + virtual ~VTypeRange() = 0; - VType*clone() const { return new VTypeRange(base_->clone(), start_, end_); } + bool write_std_types(std::ostream&fd) const; + int emit_def(std::ostream&out, perm_string name) const; // Get the type that is limited by the range. - inline const VType* base_type() const { return base_; } + inline const VType*base_type() const { return base_; } + + private: + const VType*base_; +}; + +class VTypeRangeConst : public VTypeRange { + + public: + VTypeRangeConst(const VType*base, int64_t end, int64_t start); + + VType*clone() const { + return new VTypeRangeConst(base_type()->clone(), start_, end_); + } public: // Virtual methods void write_to_stream(std::ostream&fd) const; - int emit_def(std::ostream&out, perm_string name) const; private: - const VType*base_; - int64_t start_, end_; + const int64_t start_, end_; +}; + +class VTypeRangeExpr : public VTypeRange { + + public: + VTypeRangeExpr(const VType*base, Expression*end, Expression*start, bool downto); + ~VTypeRangeExpr(); + + VType*clone() const; + + public: // Virtual methods + void write_to_stream(std::ostream&fd) const; + + private: + // Boundaries + Expression*start_, *end_; + + // Range direction (downto/to) + bool downto_; }; class VTypeEnum : public VType { diff --git a/vhdlpp/vtype_stream.cc b/vhdlpp/vtype_stream.cc index 0b4a12f1e2..96d9eff4d7 100644 --- a/vhdlpp/vtype_stream.cc +++ b/vhdlpp/vtype_stream.cc @@ -171,21 +171,41 @@ void VTypePrimitive::write_to_stream(ostream&fd) const } } -void VTypeRange::write_to_stream(ostream&fd) const +bool VTypeRange::write_std_types(ostream&fd) const { - // Detect some special cases that can be written as ieee or - // standard types. - if (const VTypePrimitive*tmp = dynamic_cast (base_)) { - if (tmp->type()==VTypePrimitive::NATURAL) { - fd << "natural"; - return; - } - } + // Detect some special cases that can be written as ieee or + // standard types. + if (const VTypePrimitive*tmp = dynamic_cast(base_)) { + if (tmp->type()==VTypePrimitive::NATURAL) { + fd << "natural"; + return true; + } + } + + return false; +} - base_->write_to_stream(fd); - fd << " range " << start_; - fd << (start_ < end_ ? " to " : " downto "); - fd << end_; +void VTypeRangeConst::write_to_stream(ostream&fd) const +{ + if(write_std_types(fd)) + return; + + base_type()->write_to_stream(fd); + fd << " range " << start_; + fd << (start_ < end_ ? " to " : " downto "); + fd << end_; +} + +void VTypeRangeExpr::write_to_stream(ostream&fd) const +{ + if(write_std_types(fd)) + return; + + base_type()->write_to_stream(fd); + fd << " range "; + start_->write_to_stream(fd); + fd << (downto_ ? " downto " : " to "); + end_->write_to_stream(fd); } void VTypeRecord::write_to_stream(ostream&fd) const