From d9fea802da0a534b669f00cbbd5bf505a1ba431a Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 5 May 2013 19:05:46 -0700 Subject: [PATCH 01/21] Function declarations in packages This is still basic. Definitions are still not done. --- vhdlpp/debug.cc | 61 +++++++++++++++++++++++++++++++++++++++++--- vhdlpp/library.cc | 10 ++++++-- vhdlpp/package.cc | 9 +++++++ vhdlpp/parse.y | 23 ++++++++++++++--- vhdlpp/parse_wrap.h | 1 + vhdlpp/scope.cc | 21 ++++++++++++++- vhdlpp/scope.h | 18 ++++++++++--- vhdlpp/subprogram.cc | 54 +++++++++++++++++++++++++++++++++++++++ vhdlpp/subprogram.h | 51 ++++++++++++++++++++++++++++++++++++ vhdlpp/vtype.cc | 2 +- vhdlpp/vtype.h | 3 ++- 11 files changed, 237 insertions(+), 16 deletions(-) create mode 100644 vhdlpp/subprogram.cc create mode 100644 vhdlpp/subprogram.h diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index 972150778..c85b868c3 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -22,6 +22,7 @@ # include "architec.h" # include "expression.h" # include "parse_types.h" +# include "sequential.h" # include "vsignal.h" # include "vtype.h" # include @@ -138,6 +139,19 @@ void Scope::dump_scope(ostream&out) const cur->second->dump(out, 3); else out << " signal " << cur->first.str() << ": ???" << endl; + } + // Dump subprograms + for (map::const_iterator cur = old_subprograms_.begin() + ; cur != old_subprograms_.end() ; ++cur) { + out << " subprogram " << cur->first << " is" << endl; + cur->second->dump(out); + out << " end subprogram " << cur->first << endl; + } + for (map::const_iterator cur = new_subprograms_.begin() + ; cur != new_subprograms_.end() ; ++cur) { + out << " subprogram " << cur->first << " is" << endl; + cur->second->dump(out); + out << " end subprogram " << cur->first << endl; } // Dump component declarations for (map::const_iterator cur = old_components_.begin() @@ -148,10 +162,11 @@ void Scope::dump_scope(ostream&out) const out << " end component " << cur->first << endl; } for (map::const_iterator cur = new_components_.begin() - ; cur != new_components_.end() ; ++cur) { - out << " component " << cur->first << " is" << endl; - cur->second->dump_ports(out); - out << " end component " << cur->first << endl; + ; cur != new_components_.end() ; ++cur) { + out << " component " << cur->first << " is" << endl; + cur->second->dump_generics(out); + cur->second->dump_ports(out); + out << " end component " << cur->first << endl; } } @@ -436,3 +451,41 @@ ostream& ExpInteger::dump_inline(ostream&out) const out << value_; return out; } + +void Subprogram::dump(ostream&fd) const +{ + fd << " " << name_; + + if (ports_->empty()) { + fd << "()"; + + } else { + fd << "("; + + list::const_iterator cur = ports_->begin(); + InterfacePort*curp = *cur; + fd << curp->name << ":"; + curp->type->show(fd); + + for (++ cur ; cur != ports_->end() ; ++ cur) { + curp = *cur; + fd << "; " << curp->name << ":"; + curp->type->show(fd); + } + fd << ")"; + } + + fd << " return "; + return_type_->show(fd); + fd << endl; + + if (statements_== 0 || statements_->empty()) { + fd << " " << endl; + } else { + for (list::const_iterator cur = statements_->begin() + ; cur != statements_->end() ; ++cur) { + SequentialStmt*curp = *cur; + curp->dump(fd, 8); + } + } +} diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index 435778020..d009446bf 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -322,11 +322,13 @@ const VTypePrimitive* primitive_BOOLEAN = new VTypePrimitive(VTypePrimitive::BO const VTypePrimitive* primitive_BIT = new VTypePrimitive(VTypePrimitive::BIT); const VTypePrimitive* primitive_INTEGER = new VTypePrimitive(VTypePrimitive::INTEGER); const VTypePrimitive* primitive_STDLOGIC = new VTypePrimitive(VTypePrimitive::STDLOGIC); +const VTypePrimitive* primitive_CHARACTER= new VTypePrimitive(VTypePrimitive::CHARACTER); const VTypeRange* primitive_NATURAL = new VTypeRange(primitive_INTEGER, INT64_MAX, 0); -const VTypeArray* primitive_BIT_VECTOR = new VTypeArray(primitive_BIT, vector (1)); -const VTypeArray* primitive_BOOL_VECTOR = new VTypeArray(primitive_BOOLEAN, vector (1)); +static const VTypeArray* primitive_BIT_VECTOR = new VTypeArray(primitive_BIT, vector (1)); +static const VTypeArray* primitive_BOOL_VECTOR = new VTypeArray(primitive_BOOLEAN, vector (1)); +static const VTypeArray* primitive_STRING = new VTypeArray(primitive_CHARACTER, vector (1)); void generate_global_types(ActiveScope*res) { @@ -334,7 +336,9 @@ void generate_global_types(ActiveScope*res) res->bind_name(perm_string::literal("bit"), primitive_BIT); res->bind_name(perm_string::literal("integer"), primitive_INTEGER); res->bind_name(perm_string::literal("std_logic"), primitive_STDLOGIC); + res->bind_name(perm_string::literal("character"), primitive_CHARACTER); res->bind_name(perm_string::literal("bit_vector"),primitive_BOOL_VECTOR); + res->bind_name(perm_string::literal("string"), primitive_STRING); res->bind_name(perm_string::literal("natural"), primitive_NATURAL); } @@ -344,7 +348,9 @@ bool is_global_type(perm_string name) if (name == "bit") return true; if (name == "integer") return true; if (name == "std_logic") return true; + if (name == "character") return true; if (name == "bit_vector") return true; + if (name == "string") return true; if (name == "natural") return true; return false; } diff --git a/vhdlpp/package.cc b/vhdlpp/package.cc index 338bbddae..2dd43ded3 100644 --- a/vhdlpp/package.cc +++ b/vhdlpp/package.cc @@ -104,6 +104,15 @@ void Package::write_to_stream(ostream&fd) const fd << ";" << endl; } + for (map::const_iterator cur = old_subprograms_.begin() + ; cur != old_subprograms_.end() ; ++cur) { + cur->second->write_to_stream(fd); + } + for (map::const_iterator cur = new_subprograms_.begin() + ; cur != new_subprograms_.end() ; ++cur) { + cur->second->write_to_stream(fd); + } + for (map::const_iterator cur = old_components_.begin() ; cur != old_components_.end() ; ++cur) { diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 3c4d0b174..e15c199ae 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -34,7 +34,8 @@ # include "architec.h" # include "expression.h" # include "sequential.h" -# include "package.h" +# include "subprogram.h" +# include "package.h" # include "vsignal.h" # include "vtype.h" # include @@ -234,6 +235,8 @@ static list* record_elements(list*names, Architecture::Statement* arch_statement; std::list* arch_statement_list; + + Subprogram*subprogram; }; /* The keywords are all tokens. */ @@ -341,6 +344,8 @@ static list* record_elements(list*names, %type else_when_waveform %type else_when_waveforms +%type function_specification subprogram_specification + %% /* The design_file is the root for the VHDL parse. This rule is also @@ -1143,6 +1148,15 @@ for_generate_statement function_specification /* IEEE 1076-2008 P4.2.1 */ : K_function IDENTIFIER '(' interface_list ')' K_return IDENTIFIER + { perm_string type_name = lex_strings.make($7); + perm_string name = lex_strings.make($2); + const VType*type_mark = active_scope->find_type(type_name); + Subprogram*tmp = new Subprogram(name, $4, type_mark); + FILE_NAME(tmp,@1); + delete[]$2; + delete[]$7; + $$ = tmp; + } ; generate_statement /* IEEE 1076-2008 P11.8 */ @@ -2057,6 +2071,7 @@ subprogram_body /* IEEE 1076-2008 P4.3 */ K_begin subprogram_statement_part K_end subprogram_kind_opt identifier_opt ';' { sorrymsg(@2, "Subprogram bodies not supported.\n"); + if ($1) delete $1; if ($8) delete[]$8; } @@ -2066,14 +2081,14 @@ subprogram_body /* IEEE 1076-2008 P4.3 */ subprogram_kind_opt identifier_opt ';' { errormsg(@2, "Syntax errors in subprogram body.\n"); yyerrok; + if ($1) delete $1; if ($8) delete[]$8; } ; subprogram_declaration : subprogram_specification ';' - { sorrymsg(@1, "Subprogram specifications not supported.\n"); - } + { if ($1) active_scope->bind_name($1->name(), $1); } ; subprogram_declarative_item /* IEEE 1079-2008 P4.3 */ @@ -2098,7 +2113,7 @@ subprogram_kind /* IEEE 1076-2008 P4.3 */ subprogram_kind_opt : subprogram_kind | ; subprogram_specification - : function_specification + : function_specification { $$ = $1; } ; /* This is an implementation of the rule: diff --git a/vhdlpp/parse_wrap.h b/vhdlpp/parse_wrap.h index d129fec43..ceca8439e 100644 --- a/vhdlpp/parse_wrap.h +++ b/vhdlpp/parse_wrap.h @@ -31,6 +31,7 @@ # include "architec.h" # include "expression.h" # include "sequential.h" +# include "subprogram.h" # include "parse_types.h" class VType; diff --git a/vhdlpp/scope.cc b/vhdlpp/scope.cc index 0455f7a88..7d5ed1c8b 100644 --- a/vhdlpp/scope.cc +++ b/vhdlpp/scope.cc @@ -57,6 +57,11 @@ ScopeBase::ScopeBase(const ScopeBase&ref) insert_iterator >( old_types_, old_types_.end()) ); + merge(ref.old_subprograms_.begin(), ref.old_subprograms_.end(), + ref.new_subprograms_.begin(), ref.new_subprograms_.end(), + insert_iterator >( + old_subprograms_, old_subprograms_.end()) + ); } ScopeBase::~ScopeBase() @@ -76,6 +81,7 @@ void ScopeBase::cleanup() delete_all(new_components_); delete_all(new_types_); delete_all(new_constants_); + delete_all(new_subprograms_); } const VType*ScopeBase::find_type(perm_string by_name) @@ -146,13 +152,26 @@ void ScopeBase::do_use_from(const ScopeBase*that) continue; old_components_[cur->first] = cur->second; } - for (map::const_iterator cur = that->new_components_.begin() + for (map::const_iterator cur = that->new_components_.begin() ; cur != that->new_components_.end() ; ++ cur) { if (cur->second == 0) continue; old_components_[cur->first] = cur->second; } + for (map::const_iterator cur = that->old_subprograms_.begin() + ; cur != that->old_subprograms_.end() ; ++ cur) { + if (cur->second == 0) + continue; + old_subprograms_[cur->first] = cur->second; + } + for (map::const_iterator cur = that->new_subprograms_.begin() + ; cur != that->new_subprograms_.end() ; ++ cur) { + if (cur->second == 0) + continue; + old_subprograms_[cur->first] = cur->second; + } + for (map::const_iterator cur = that->old_types_.begin() ; cur != that->old_types_.end() ; ++ cur) { if (cur->second == 0) diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index e0fbfb0b3..e07e06ff6 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -23,12 +23,14 @@ # include # include # include "StringHeap.h" -# include "entity.h" -# include "expression.h" -# include "vsignal.h" +# include "entity.h" +# include "expression.h" +# include "subprogram.h" +# include "vsignal.h" class Architecture; class ComponentBase; +class Subprogram; class VType; template @@ -89,6 +91,9 @@ class ScopeBase { std::map old_constants_; //previous scopes std::map new_constants_; //current scope + std::map old_subprograms_; //previous scopes + std::map new_subprograms_; //current scope + void do_use_from(const ScopeBase*that); }; @@ -171,6 +176,13 @@ class ActiveScope : public ScopeBase { new_constants_[name] = new const_t(obj, val); } + void bind_name(perm_string name, Subprogram*obj) + { map::iterator it; + if((it = old_subprograms_.find(name)) != old_subprograms_.end() ) + old_subprograms_.erase(it); + new_subprograms_[name] = obj;; + } + void bind(Entity*ent) { context_entity_ = ent; } diff --git a/vhdlpp/subprogram.cc b/vhdlpp/subprogram.cc new file mode 100644 index 000000000..3aa1fb94b --- /dev/null +++ b/vhdlpp/subprogram.cc @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * 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. + */ + +# include "subprogram.h" +# include "entity.h" +# include "vtype.h" + +using namespace std; + +Subprogram::Subprogram(perm_string nam, list*ports, + const VType*return_type) +: name_(nam), ports_(ports), return_type_(return_type), statements_(0) +{ +} + +Subprogram::~Subprogram() +{ +} + +void Subprogram::write_to_stream(ostream&fd) const +{ + fd << " function " << name_ << "("; + if (ports_ && ! ports_->empty()) { + list::const_iterator cur = ports_->begin(); + InterfacePort*curp = *cur; + fd << curp->name << " : "; + curp->type->write_to_stream(fd); + for (++cur ; cur != ports_->end() ; ++cur) { + curp = *cur; + fd << "; " << curp->name << " : "; + curp->type->write_to_stream(fd); + } + } + fd << ") return "; + return_type_->write_to_stream(fd); + fd << ";" << endl; +} diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h new file mode 100644 index 000000000..afd4764eb --- /dev/null +++ b/vhdlpp/subprogram.h @@ -0,0 +1,51 @@ +#ifndef __subprogram_H +#define __subprogram_H +/* + * Copyright (c) 2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * 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. + */ + +# include "StringHeap.h" +# include "LineInfo.h" +# include +# include + +class InterfacePort; +class SequentialStmt; +class VType; + +class Subprogram : public LineInfo { + + public: + Subprogram(perm_string name, std::list*ports, + const VType*return_type); + ~Subprogram(); + + inline const perm_string&name() const { return name_; } + + void write_to_stream(std::ostream&fd) const; + void dump(std::ostream&fd) const; + + private: + perm_string name_; + std::list*ports_; + const VType*return_type_; + std::list*statements_; +}; + +#endif diff --git a/vhdlpp/vtype.cc b/vhdlpp/vtype.cc index b8e704d11..3c6d78241 100644 --- a/vhdlpp/vtype.cc +++ b/vhdlpp/vtype.cc @@ -32,7 +32,7 @@ VType::~VType() void VType::show(ostream&out) const { - out << typeid(*this).name(); + write_to_stream(out); } VTypePrimitive::VTypePrimitive(VTypePrimitive::type_t tt) diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index 4da22363d..3edbe44a2 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -112,7 +112,7 @@ class VTypeERROR : public VType { class VTypePrimitive : public VType { public: - enum type_t { BOOLEAN, BIT, INTEGER, STDLOGIC }; + enum type_t { BOOLEAN, BIT, INTEGER, STDLOGIC, CHARACTER }; public: VTypePrimitive(type_t); @@ -134,6 +134,7 @@ extern const VTypePrimitive* primitive_BOOLEAN; extern const VTypePrimitive* primitive_BIT; extern const VTypePrimitive* primitive_INTEGER; extern const VTypePrimitive* primitive_STDLOGIC; +extern const VTypePrimitive* primitive_CHARACTER; /* * An array is a compound N-dimensional array of element type. The From 7f7decde039abb1a1b69de626ead3427a776b32e Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 11 May 2013 20:00:00 -0700 Subject: [PATCH 02/21] Basic structure for emitting packages. --- vhdlpp/compiler.h | 1 + vhdlpp/library.cc | 24 ++++++++++++++ vhdlpp/main.cc | 11 +++++-- vhdlpp/package.cc | 7 +++++ vhdlpp/package.h | 9 +++++- vhdlpp/package_emit.cc | 66 +++++++++++++++++++++++++++++++++++++++ vhdlpp/subprogram.h | 3 ++ vhdlpp/subprogram_emit.cc | 56 +++++++++++++++++++++++++++++++++ vhdlpp/vtype_emit.cc | 13 ++++++-- 9 files changed, 185 insertions(+), 5 deletions(-) create mode 100644 vhdlpp/package_emit.cc create mode 100644 vhdlpp/subprogram_emit.cc diff --git a/vhdlpp/compiler.h b/vhdlpp/compiler.h index f0ae81ad5..380ca0f01 100644 --- a/vhdlpp/compiler.h +++ b/vhdlpp/compiler.h @@ -36,5 +36,6 @@ extern StringHeapLex filename_strings; extern void library_set_work_path(const char*work_path); extern void library_add_directory(const char*directory); +extern int emit_packages(void); #endif diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index d009446bf..d95a7b47b 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -134,6 +134,8 @@ void library_save_package(perm_string parse_library_name, Package*pack) // library right now, then store it in the work library. if (parse_library_name.str() == 0) store_package_in_work(pack); + else + pack->set_library(parse_library_name); } static void import_library_name(const YYLTYPE&loc, perm_string name) @@ -369,3 +371,25 @@ static void store_package_in_work(const Package*pack) pack->write_to_stream(file); } + +static int emit_packages(perm_string lib_name, const map&packages) +{ + int errors = 0; + for (map::const_iterator cur = packages.begin() + ; cur != packages.end() ; ++cur) { + errors += cur->second->emit_package(cout); + } + + return errors; +} + +int emit_packages(void) +{ + int errors = 0; + for (map::iterator cur = libraries.begin() + ; cur != libraries.end() ; ++cur) { + errors += emit_packages(cur->first, cur->second.packages); + } + + return 0; +} diff --git a/vhdlpp/main.cc b/vhdlpp/main.cc index ce3fa2df6..45fb02e9d 100644 --- a/vhdlpp/main.cc +++ b/vhdlpp/main.cc @@ -218,17 +218,24 @@ int main(int argc, char*argv[]) } if (errors > 0) { - parser_cleanup(); + parser_cleanup(); return 2; } errors = elaborate_entities(); if (errors > 0) { fprintf(stderr, "%d errors elaborating design.\n", errors); - parser_cleanup(); + parser_cleanup(); return 3; } + errors = emit_packages(); + if (errors > 0) { + fprintf(stderr, "%d errors emitting packages.\n", errors); + parser_cleanup(); + return 4; + } + errors = emit_entities(); if (errors > 0) { fprintf(stderr, "%d errors emitting design.\n", errors); diff --git a/vhdlpp/package.cc b/vhdlpp/package.cc index 2dd43ded3..6541b2be8 100644 --- a/vhdlpp/package.cc +++ b/vhdlpp/package.cc @@ -20,6 +20,7 @@ # include "package.h" # include "entity.h" # include "parse_misc.h" +# include "ivl_assert.h" Package::Package(perm_string n, const ScopeBase&ref) : Scope(ref), name_(n) @@ -31,6 +32,12 @@ Package::~Package() ScopeBase::cleanup(); } +void Package::set_library(perm_string lname) +{ + ivl_assert(*this, from_library_.str() == 0); + from_library_ = lname; +} + /* * The Package::write_to_stream is used to write the package to the * work space (or library) so writes proper VHDL that the library diff --git a/vhdlpp/package.h b/vhdlpp/package.h index 8f9fd04ae..bec82a606 100644 --- a/vhdlpp/package.h +++ b/vhdlpp/package.h @@ -1,7 +1,7 @@ #ifndef __package_H #define __package_H /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -29,12 +29,19 @@ class Package : public Scope, public LineInfo { Package(perm_string name, const ScopeBase&ref); ~Package(); + // The the library from which this package came. Having a + // source library influences the emit_package() method. + void set_library(perm_string); + perm_string name() const { return name_; } // This method writes a package header to a library file. void write_to_stream(std::ostream&fd) const; + int emit_package(std::ostream&fd) const; + private: + perm_string from_library_; perm_string name_; }; diff --git a/vhdlpp/package_emit.cc b/vhdlpp/package_emit.cc new file mode 100644 index 000000000..f0b2751b6 --- /dev/null +++ b/vhdlpp/package_emit.cc @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * 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. + */ + +# include "package.h" +# include + +using namespace std; + +int Package::emit_package(ostream&fd) const +{ + // Don't emit the package if there is nothing in it that SV + // cares about. + if (new_types_.empty() && old_subprograms_.empty() && new_subprograms_.empty()) + return 0; + + // If this package was imported from a library, then do not + // emit it again. + if (from_library_.str() != 0) { + fd << "/* Suppress package " << name() + << " from library " << from_library_ << " */" << endl; + return 0; + } + + int errors = 0; + + fd << "package \\" << name() << " ;" << endl; + + // Only emit types that were defined within this package. Skip + // the types that were imported from elsewhere. + for (map::const_iterator cur = new_types_.begin() + ; cur != new_types_.end() ; ++ cur) { + errors += cur->second->emit_def(fd); + fd << " " << cur->first << " ;" << endl; + } + + for (map::const_iterator cur = old_subprograms_.begin() + ; cur != old_subprograms_.end() ; ++ cur) { + errors += cur->second->emit_package(fd); + } + + for (map::const_iterator cur = new_subprograms_.begin() + ; cur != new_subprograms_.end() ; ++ cur) { + errors += cur->second->emit_package(fd); + } + + fd << "endpackage" << endl; + + return errors; +} diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h index afd4764eb..7ec691d32 100644 --- a/vhdlpp/subprogram.h +++ b/vhdlpp/subprogram.h @@ -38,6 +38,9 @@ class Subprogram : public LineInfo { inline const perm_string&name() const { return name_; } + // Emit a definition as it would show up in a package. + int emit_package(std::ostream&fd) const; + void write_to_stream(std::ostream&fd) const; void dump(std::ostream&fd) const; diff --git a/vhdlpp/subprogram_emit.cc b/vhdlpp/subprogram_emit.cc new file mode 100644 index 000000000..e70351a4c --- /dev/null +++ b/vhdlpp/subprogram_emit.cc @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * 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. + */ + +# include "subprogram.h" +# include "sequential.h" +# include "vtype.h" +# include + +using namespace std; + +int Subprogram::emit_package(ostream&fd) const +{ + int errors = 0; + + if (return_type_) { + fd << "function "; + return_type_->emit_def(fd); + fd << " " << name_; + fd << ";" << endl; + } else { + fd << "task " << name_ << ";" << endl; + } + + if (statements_) { + for (list::const_iterator cur = statements_->begin() + ; cur != statements_->end() ; ++cur) { + errors += (*cur)->emit(fd, 0, 0); + } + } else { + fd << " begin /* empty body */ end" << endl; + } + + if (return_type_) + fd << "endfunction" << endl; + else + fd << "endtask" << endl; + + return errors; +} diff --git a/vhdlpp/vtype_emit.cc b/vhdlpp/vtype_emit.cc index a3ca1add5..7508ee8c4 100644 --- a/vhdlpp/vtype_emit.cc +++ b/vhdlpp/vtype_emit.cc @@ -88,9 +88,15 @@ int VTypeArray::emit_def(ostream&out) const cur = dims.front(); dims.pop_front(); out << "["; - errors += cur->dimension(0).msb()->emit(out, 0, 0); + if (cur->dimension(0).msb()) + errors += cur->dimension(0).msb()->emit(out, 0, 0); + else + out << "?error?"; out << ":"; - errors += cur->dimension(0).lsb()->emit(out, 0, 0); + if (cur->dimension(0).lsb()) + errors += cur->dimension(0).lsb()->emit(out, 0, 0); + else + out << "?error?"; out << "]"; } @@ -130,6 +136,9 @@ int VTypePrimitive::emit_primitive_type(ostream&out) const case INTEGER: out << "bool [31:0]"; break; + case CHARACTER: + out << "char"; + break; default: assert(0); break; From 13be45bd73bb3a64363fc4dbb28f52cc689346ad Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 12 May 2013 15:31:48 -0700 Subject: [PATCH 03/21] Fix dump of primitive CHARACTER types. --- vhdlpp/vtype.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vhdlpp/vtype.cc b/vhdlpp/vtype.cc index 3c6d78241..34787c6a0 100644 --- a/vhdlpp/vtype.cc +++ b/vhdlpp/vtype.cc @@ -53,6 +53,9 @@ void VTypePrimitive::show(ostream&out) const case BIT: out << "BIT"; break; + case CHARACTER: + out << "CHARACTER"; + break; case INTEGER: out << "INTEGER"; break; From 6394a4d78d8268e0f7f990ca63de1a03690f8af9 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 12 May 2013 19:17:12 -0700 Subject: [PATCH 04/21] Rework scope types and constants so we can tell imported from local names. The package emit of types and constants needs to know which names are from the current type and which are imported from libraries. Rework the scope handling of those names so that the information is preserved. --- vhdlpp/architec.cc | 2 +- vhdlpp/architec.h | 2 +- vhdlpp/architec_elaborate.cc | 8 ++--- vhdlpp/architec_emit.cc | 12 +++---- vhdlpp/debug.cc | 23 ++++++++----- vhdlpp/expression.h | 5 +++ vhdlpp/expression_emit.cc | 14 ++++++++ vhdlpp/library.cc | 29 ++++++++-------- vhdlpp/package.cc | 55 ++++++++++++------------------ vhdlpp/package.h | 3 +- vhdlpp/package_emit.cc | 30 ++++++++++++----- vhdlpp/scope.cc | 65 +++++++++++++++--------------------- vhdlpp/scope.h | 40 ++++++++++++++-------- 13 files changed, 159 insertions(+), 129 deletions(-) diff --git a/vhdlpp/architec.cc b/vhdlpp/architec.cc index acf9eafad..f223e8b90 100644 --- a/vhdlpp/architec.cc +++ b/vhdlpp/architec.cc @@ -26,7 +26,7 @@ using namespace std; -Architecture::Architecture(perm_string name, const ScopeBase&ref, +Architecture::Architecture(perm_string name, const ActiveScope&ref, list&s) : Scope(ref), name_(name) { diff --git a/vhdlpp/architec.h b/vhdlpp/architec.h index 33224f485..594f350eb 100644 --- a/vhdlpp/architec.h +++ b/vhdlpp/architec.h @@ -63,7 +63,7 @@ class Architecture : public Scope, public LineInfo { public: // Create an architecture from its name and its statements. // NOTE: The statement list passed in is emptied. - Architecture(perm_string name, const ScopeBase&ref, + Architecture(perm_string name, const ActiveScope&ref, std::list&s); ~Architecture(); diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index 0e85dd05d..e7308f96e 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -32,12 +32,12 @@ int Architecture::elaborate(Entity*entity) // from the constant declaration itself. Elaborate the value // expression with the declared type. - for (map::iterator cur = old_constants_.begin() - ; cur != old_constants_.end() ; ++cur) { + for (map::iterator cur = use_constants_.begin() + ; cur != use_constants_.end() ; ++cur) { cur->second->val->elaborate_expr(entity, this, cur->second->typ); } - for (map::iterator cur = new_constants_.begin() - ; cur != new_constants_.end() ; ++cur) { + for (map::iterator cur = cur_constants_.begin() + ; cur != cur_constants_.end() ; ++cur) { cur->second->val->elaborate_expr(entity, this, cur->second->typ); } diff --git a/vhdlpp/architec_emit.cc b/vhdlpp/architec_emit.cc index 0f517294b..b53f94acf 100644 --- a/vhdlpp/architec_emit.cc +++ b/vhdlpp/architec_emit.cc @@ -69,8 +69,8 @@ int Architecture::emit(ostream&out, Entity*entity) // of the full definition. typedef_context_t typedef_ctx; - for (map::iterator cur = old_types_.begin() - ; cur != old_types_.end() ; ++cur) { + for (map::iterator cur = cur_types_.begin() + ; cur != cur_types_.end() ; ++cur) { const VTypeDef*def = dynamic_cast(cur->second); if (def == 0) @@ -79,15 +79,15 @@ int Architecture::emit(ostream&out, Entity*entity) errors += def->emit_typedef(out, typedef_ctx); } - for (map::iterator cur = old_constants_.begin() - ; cur != old_constants_.end() ; ++cur) { + for (map::iterator cur = use_constants_.begin() + ; cur != use_constants_.end() ; ++cur) { out << "localparam " << cur->first << " = "; errors += cur->second->val->emit(out, entity, this); out << ";" << endl; } - for (map::iterator cur = new_constants_.begin() - ; cur != new_constants_.end() ; ++cur) { + for (map::iterator cur = cur_constants_.begin() + ; cur != cur_constants_.end() ; ++cur) { out << "localparam " << cur->first << " = "; errors += cur->second->val->emit(out, entity, this); diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index c85b868c3..0a5dfc6c8 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -101,31 +101,36 @@ void ComponentBase::dump_ports(ostream&out, int indent) const void Scope::dump_scope(ostream&out) const { // Dump types - for (map::const_iterator cur = old_types_.begin() - ; cur != old_types_.end() ; ++cur) { + out << " -- imported types" << endl; + for (map::const_iterator cur = use_types_.begin() + ; cur != use_types_.end() ; ++cur) { out << " " << cur->first << ": "; cur->second->show(out); out << endl; } - for (map::const_iterator cur = new_types_.begin() - ; cur != new_types_.end() ; ++cur) { + out << " -- Types from this scope" << endl; + for (map::const_iterator cur = cur_types_.begin() + ; cur != cur_types_.end() ; ++cur) { out << " " << cur->first << ": "; cur->second->show(out); out << endl; } // Dump constants - for (map::const_iterator cur = old_constants_.begin() - ; cur != old_constants_.end() ; ++cur) { + out << " -- imported constants" << endl; + for (map::const_iterator cur = use_constants_.begin() + ; cur != use_constants_.end() ; ++cur) { out << " constant " << cur->first << " = "; out << endl; } - for (map::const_iterator cur = new_constants_.begin() - ; cur != new_constants_.end() ; ++cur) { + out << " -- Constants from this scope" << endl; + for (map::const_iterator cur = cur_constants_.begin() + ; cur != cur_constants_.end() ; ++cur) { out << " constant " << cur->first << " = "; out << endl; } // Dump signal declarations + out << " -- Signals" << endl; for (map::const_iterator cur = old_signals_.begin() ; cur != old_signals_.end() ; ++cur) { if (cur->second) @@ -141,6 +146,7 @@ void Scope::dump_scope(ostream&out) const out << " signal " << cur->first.str() << ": ???" << endl; } // Dump subprograms + out << " -- Subprograms" << endl; for (map::const_iterator cur = old_subprograms_.begin() ; cur != old_subprograms_.end() ; ++cur) { out << " subprogram " << cur->first << " is" << endl; @@ -154,6 +160,7 @@ void Scope::dump_scope(ostream&out) const out << " end subprogram " << cur->first << endl; } // Dump component declarations + out << " -- Components" << endl; for (map::const_iterator cur = old_components_.begin() ; cur != old_components_.end() ; ++cur) { out << " component " << cur->first << " is" << endl; diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index 0271abe37..6d24335f0 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -90,6 +90,10 @@ class Expression : public LineInfo { // class fills in the details of what exactly happened. virtual int emit(ostream&out, Entity*ent, Architecture*arc) =0; + // The emit_package virtual message is similar, but is called + // in a package context and to emit SV packages. + virtual int emit_package(std::ostream&out); + // The evaluate virtual method tries to evaluate expressions // to constant literal values. Return true and set the val // argument if the evaluation works, or return false if it @@ -478,6 +482,7 @@ class ExpInteger : public Expression { int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); void write_to_stream(std::ostream&fd); int emit(ostream&out, Entity*ent, Architecture*arc); + int emit_package(std::ostream&out); bool is_primary(void) const; bool evaluate(ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index c0d22210b..2c1b43114 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -37,6 +37,14 @@ int Expression::emit(ostream&out, Entity*, Architecture*) return 1; } +int Expression::emit_package(ostream&out) +{ + out << " /* " << get_fileline() << ": internal error: " + << "I don't know how to emit_package this expression! " + << "type=" << typeid(*this).name() << " */ "; + return 1; +} + bool Expression::is_primary(void) const { return false; @@ -565,6 +573,12 @@ int ExpInteger::emit(ostream&out, Entity*, Architecture*) return 0; } +int ExpInteger::emit_package(ostream&out) +{ + out << value_; + return 0; +} + bool ExpInteger::is_primary(void) const { return true; diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index d95a7b47b..01b5e0ee4 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -1,5 +1,6 @@ /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -256,7 +257,7 @@ static void import_ieee_use_std_logic_1164(ActiveScope*res, perm_string name) if (all_flag || name == "std_logic_vector") { vector dims (1); - res->bind_name(perm_string::literal("std_logic_vector"), + res->use_name(perm_string::literal("std_logic_vector"), new VTypeArray(primitive_STDLOGIC, dims, false)); } } @@ -271,12 +272,12 @@ static void import_ieee_use_numeric_bit(ActiveScope*res, perm_string name) if (all_flag || name == "signed") { vector dims (1); - res->bind_name(perm_string::literal("signed"), + res->use_name(perm_string::literal("signed"), new VTypeArray(primitive_STDLOGIC, dims, true)); } if (all_flag || name == "unsigned") { vector dims (1); - res->bind_name(perm_string::literal("unsigned"), + res->use_name(perm_string::literal("unsigned"), new VTypeArray(primitive_BIT, dims, false)); } } @@ -287,12 +288,12 @@ static void import_ieee_use_numeric_std(ActiveScope*res, perm_string name) if (all_flag || name == "signed") { vector dims (1); - res->bind_name(perm_string::literal("signed"), + res->use_name(perm_string::literal("signed"), new VTypeArray(primitive_STDLOGIC, dims, true)); } if (all_flag || name == "unsigned") { vector dims (1); - res->bind_name(perm_string::literal("unsigned"), + res->use_name(perm_string::literal("unsigned"), new VTypeArray(primitive_STDLOGIC, dims, false)); } } @@ -334,14 +335,14 @@ static const VTypeArray* primitive_STRING = new VTypeArray(primitive_CHARACTER, void generate_global_types(ActiveScope*res) { - res->bind_name(perm_string::literal("boolean"), primitive_BOOLEAN); - res->bind_name(perm_string::literal("bit"), primitive_BIT); - res->bind_name(perm_string::literal("integer"), primitive_INTEGER); - res->bind_name(perm_string::literal("std_logic"), primitive_STDLOGIC); - res->bind_name(perm_string::literal("character"), primitive_CHARACTER); - res->bind_name(perm_string::literal("bit_vector"),primitive_BOOL_VECTOR); - res->bind_name(perm_string::literal("string"), primitive_STRING); - res->bind_name(perm_string::literal("natural"), primitive_NATURAL); + res->use_name(perm_string::literal("boolean"), primitive_BOOLEAN); + res->use_name(perm_string::literal("bit"), primitive_BIT); + res->use_name(perm_string::literal("integer"), primitive_INTEGER); + res->use_name(perm_string::literal("std_logic"), primitive_STDLOGIC); + res->use_name(perm_string::literal("character"), primitive_CHARACTER); + res->use_name(perm_string::literal("bit_vector"),primitive_BOOL_VECTOR); + res->use_name(perm_string::literal("string"), primitive_STRING); + res->use_name(perm_string::literal("natural"), primitive_NATURAL); } bool is_global_type(perm_string name) diff --git a/vhdlpp/package.cc b/vhdlpp/package.cc index 6541b2be8..aea43c1bf 100644 --- a/vhdlpp/package.cc +++ b/vhdlpp/package.cc @@ -1,5 +1,6 @@ /* - * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -22,7 +23,7 @@ # include "parse_misc.h" # include "ivl_assert.h" -Package::Package(perm_string n, const ScopeBase&ref) +Package::Package(perm_string n, const ActiveScope&ref) : Scope(ref), name_(n) { } @@ -45,29 +46,30 @@ void Package::set_library(perm_string lname) */ void Package::write_to_stream(ostream&fd) const { + ivl_assert(*this, new_subprograms_.size() == 0); + fd << "package " << name_ << " is" << endl; // Start out pre-declaring all the type definitions so that // there is no confusion later in the package between types // and identifiers. - for (map::const_iterator cur = old_types_.begin() - ; cur != old_types_.end() ; ++cur) { + for (map::const_iterator cur = use_types_.begin() + ; cur != use_types_.end() ; ++cur) { + const VTypeDef*def = dynamic_cast (cur->second); + if (def == 0) + continue; + fd << "type " << cur->first << ";" << endl; + } + for (map::const_iterator cur = cur_types_.begin() + ; cur != cur_types_.end() ; ++cur) { const VTypeDef*def = dynamic_cast (cur->second); if (def == 0) continue; fd << "type " << cur->first << ";" << endl; } - for (map::const_iterator cur = new_types_.begin() - ; cur != new_types_.end() ; ++cur) { - const VTypeDef*def = dynamic_cast (cur->second); - if (def == 0) - continue; - fd << "type " << cur->first << ";" << endl; - } - - for (map::const_iterator cur = old_constants_.begin() - ; cur != old_constants_.end() ; ++ cur) { + for (map::const_iterator cur = cur_constants_.begin() + ; cur != cur_constants_.end() ; ++ cur) { fd << "constant " << cur->first << ": "; cur->second->typ->write_to_stream(fd); fd << " := "; @@ -75,17 +77,8 @@ void Package::write_to_stream(ostream&fd) const fd << ";" << endl; } - for (map::const_iterator cur = new_constants_.begin() - ; cur != new_constants_.end() ; ++ cur) { - fd << "constant " << cur->first << ": "; - cur->second->typ->write_to_stream(fd); - fd << " := "; - cur->second->val->write_to_stream(fd); - fd << ";" << endl; - } - - for (map::const_iterator cur = old_types_.begin() - ; cur != old_types_.end() ; ++cur) { + for (map::const_iterator cur = use_types_.begin() + ; cur != use_types_.end() ; ++cur) { // Do not include global types in types dump if (is_global_type(cur->first)) @@ -95,12 +88,12 @@ void Package::write_to_stream(ostream&fd) const fd << "type " << cur->first << " is "; cur->second->write_type_to_stream(fd); - fd << ";" << endl; + fd << "; -- imported" << endl; } - for (map::const_iterator cur = new_types_.begin() - ; cur != new_types_.end() ; ++cur) { + for (map::const_iterator cur = cur_types_.begin() + ; cur != cur_types_.end() ; ++cur) { - // Do not include primitive types in type dump + // Do not include global types in types dump if (is_global_type(cur->first)) continue; if (cur->first == "std_logic_vector") @@ -115,10 +108,6 @@ void Package::write_to_stream(ostream&fd) const ; cur != old_subprograms_.end() ; ++cur) { cur->second->write_to_stream(fd); } - for (map::const_iterator cur = new_subprograms_.begin() - ; cur != new_subprograms_.end() ; ++cur) { - cur->second->write_to_stream(fd); - } for (map::const_iterator cur = old_components_.begin() ; cur != old_components_.end() ; ++cur) { diff --git a/vhdlpp/package.h b/vhdlpp/package.h index bec82a606..484bea53b 100644 --- a/vhdlpp/package.h +++ b/vhdlpp/package.h @@ -2,6 +2,7 @@ #define __package_H /* * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -26,7 +27,7 @@ class Package : public Scope, public LineInfo { public: - Package(perm_string name, const ScopeBase&ref); + Package(perm_string name, const ActiveScope&ref); ~Package(); // The the library from which this package came. Having a diff --git a/vhdlpp/package_emit.cc b/vhdlpp/package_emit.cc index f0b2751b6..b4b0836a2 100644 --- a/vhdlpp/package_emit.cc +++ b/vhdlpp/package_emit.cc @@ -20,14 +20,17 @@ # include "package.h" # include +# include "ivl_assert.h" using namespace std; int Package::emit_package(ostream&fd) const { + ivl_assert(*this, new_subprograms_.empty()); + // Don't emit the package if there is nothing in it that SV // cares about. - if (new_types_.empty() && old_subprograms_.empty() && new_subprograms_.empty()) + if (cur_types_.empty() && cur_constants_.empty() && old_subprograms_.empty()) return 0; // If this package was imported from a library, then do not @@ -44,10 +47,24 @@ int Package::emit_package(ostream&fd) const // Only emit types that were defined within this package. Skip // the types that were imported from elsewhere. - for (map::const_iterator cur = new_types_.begin() - ; cur != new_types_.end() ; ++ cur) { + for (map::const_iterator cur = cur_types_.begin() + ; cur != cur_types_.end() ; ++ cur) { + fd << "typedef "; errors += cur->second->emit_def(fd); - fd << " " << cur->first << " ;" << endl; + fd << " \\" << cur->first << " ;" << endl; + } + + for (map::const_iterator cur = use_constants_.begin() + ; cur != use_constants_.end() ; ++cur) { + fd << "localparam \\" << cur->first << " = "; + errors += cur->second->val->emit_package(fd); + fd << ";" << endl; + } + for (map::const_iterator cur = cur_constants_.begin() + ; cur != cur_constants_.end() ; ++cur) { + fd << "localparam " << cur->first << " = "; + errors += cur->second->val->emit_package(fd); + fd << ";" << endl; } for (map::const_iterator cur = old_subprograms_.begin() @@ -55,11 +72,6 @@ int Package::emit_package(ostream&fd) const errors += cur->second->emit_package(fd); } - for (map::const_iterator cur = new_subprograms_.begin() - ; cur != new_subprograms_.end() ; ++ cur) { - errors += cur->second->emit_package(fd); - } - fd << "endpackage" << endl; return errors; diff --git a/vhdlpp/scope.cc b/vhdlpp/scope.cc index 7d5ed1c8b..33fdeb2f4 100644 --- a/vhdlpp/scope.cc +++ b/vhdlpp/scope.cc @@ -30,13 +30,11 @@ using namespace std; * "old_*_" variables. This clears up the "new_*_" variables to * accumulate new scope values. */ -ScopeBase::ScopeBase(const ScopeBase&ref) +ScopeBase::ScopeBase(const ActiveScope&ref) { - merge(ref.old_constants_.begin(), ref.old_constants_.end(), - ref.new_constants_.begin(), ref.new_constants_.end(), - insert_iterator >( - old_constants_, old_constants_.end()) - ); + use_constants_ = ref.use_constants_; + cur_constants_ = ref.cur_constants_; + merge(ref.old_signals_.begin(), ref.old_signals_.end(), ref.new_signals_.begin(), ref.new_signals_.end(), insert_iterator >( @@ -52,11 +50,8 @@ ScopeBase::ScopeBase(const ScopeBase&ref) insert_iterator >( old_components_, old_components_.end()) ); - merge(ref.old_types_.begin(), ref.old_types_.end(), - ref.new_types_.begin(), ref.new_types_.end(), - insert_iterator >( - old_types_, old_types_.end()) - ); + use_types_ = ref.use_types_; + cur_types_ = ref.cur_types_; merge(ref.old_subprograms_.begin(), ref.old_subprograms_.end(), ref.new_subprograms_.begin(), ref.new_subprograms_.end(), insert_iterator >( @@ -79,17 +74,17 @@ void ScopeBase::cleanup() */ delete_all(new_signals_); delete_all(new_components_); - delete_all(new_types_); - delete_all(new_constants_); + delete_all(cur_types_); + delete_all(cur_constants_); delete_all(new_subprograms_); } const VType*ScopeBase::find_type(perm_string by_name) { - map::const_iterator cur = new_types_.find(by_name); - if (cur == new_types_.end()) { - cur = old_types_.find(by_name); - if (cur == old_types_.end()) + map::const_iterator cur = cur_types_.find(by_name); + if (cur == cur_types_.end()) { + cur = use_types_.find(by_name); + if (cur == use_types_.end()) return 0; else return cur->second; @@ -99,10 +94,10 @@ const VType*ScopeBase::find_type(perm_string by_name) bool ScopeBase::find_constant(perm_string by_name, const VType*&typ, Expression*&exp) { - map::const_iterator cur = new_constants_.find(by_name); - if (cur == new_constants_.end()) { - cur = old_constants_.find(by_name); - if (cur == old_constants_.end()) + map::const_iterator cur = cur_constants_.find(by_name); + if (cur == cur_constants_.end()) { + cur = use_constants_.find(by_name); + if (cur == use_constants_.end()) return false; else { typ = cur->second->typ; @@ -144,6 +139,10 @@ Variable* ScopeBase::find_variable(perm_string by_name) const } } +/* + * This method is only used by the ActiveScope derived class to import + * definition from another scope. + */ void ScopeBase::do_use_from(const ScopeBase*that) { for (map::const_iterator cur = that->old_components_.begin() @@ -172,26 +171,16 @@ void ScopeBase::do_use_from(const ScopeBase*that) old_subprograms_[cur->first] = cur->second; } - for (map::const_iterator cur = that->old_types_.begin() - ; cur != that->old_types_.end() ; ++ cur) { + for (map::const_iterator cur = that->cur_types_.begin() + ; cur != that->cur_types_.end() ; ++ cur) { if (cur->second == 0) continue; - old_types_[cur->first] = cur->second; - } - for (map::const_iterator cur = that->new_types_.begin() - ; cur != that->new_types_.end() ; ++ cur) { - if (cur->second == 0) - continue; - old_types_[cur->first] = cur->second; + use_types_[cur->first] = cur->second; } - for (map::const_iterator cur = that->old_constants_.begin() - ; cur != that->old_constants_.end() ; ++ cur) { - old_constants_[cur->first] = cur->second; - } - for (map::const_iterator cur = that->new_constants_.begin() - ; cur != that->new_constants_.end() ; ++ cur) { - old_constants_[cur->first] = cur->second; + for (map::const_iterator cur = that->cur_constants_.begin() + ; cur != that->cur_constants_.end() ; ++ cur) { + use_constants_[cur->first] = cur->second; } } @@ -208,7 +197,7 @@ bool ActiveScope::is_vector_name(perm_string name) const return false; } -Scope::Scope(const ScopeBase&ref) +Scope::Scope(const ActiveScope&ref) : ScopeBase(ref) { } diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index e07e06ff6..7c0644817 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -1,7 +1,8 @@ #ifndef __scope_H #define __scope_H /* - * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -28,8 +29,10 @@ # include "subprogram.h" # include "vsignal.h" +class ActiveScope; class Architecture; class ComponentBase; +class Package; class Subprogram; class VType; @@ -47,7 +50,7 @@ class ScopeBase { public: ScopeBase() { } - explicit ScopeBase(const ScopeBase&ref); + explicit ScopeBase(const ActiveScope&ref); virtual ~ScopeBase() =0; const VType* find_type(perm_string by_name); @@ -68,6 +71,12 @@ class ScopeBase { for_each(c.begin(), c.end(), ::delete_pair_second()); } + // The new_*_ maps below are managed only by the ActiveScope + // derived class. When any scope is constructed from the + // ActiveScope, the new_*_ and old_*_ maps are merged and + // installed into the old_*_ maps. Thus, all other derived + // classes should only use the old_*_ maps. + // Signal declarations... std::map old_signals_; //previous scopes std::map new_signals_; //current scope @@ -78,8 +87,8 @@ class ScopeBase { std::map old_components_; //previous scopes std::map new_components_; //current scope // Type declarations... - std::map old_types_; //previous scopes - std::map new_types_; //current scope + std::map use_types_; //imported types + std::map cur_types_; //current types // Constant declarations... struct const_t { ~const_t() {delete typ; delete val;} @@ -88,8 +97,8 @@ class ScopeBase { const VType*typ; Expression*val; }; - std::map old_constants_; //previous scopes - std::map new_constants_; //current scope + std::map use_constants_; //imported constants + std::map cur_constants_; //current constants std::map old_subprograms_; //previous scopes std::map new_subprograms_; //current scope @@ -100,7 +109,7 @@ class ScopeBase { class Scope : public ScopeBase { public: - explicit Scope(const ScopeBase&ref); + explicit Scope(const ActiveScope&ref); ~Scope(); ComponentBase* find_component(perm_string by_name); @@ -128,7 +137,7 @@ class ActiveScope : public ScopeBase { ~ActiveScope() { } - void use_from(const ScopeBase*that) { do_use_from(that); } + void use_from(const Scope*that) { do_use_from(that); } // This function returns true if the name is a vectorable // name. The parser uses this to distinguish between function @@ -164,16 +173,19 @@ class ActiveScope : public ScopeBase { void bind_name(perm_string name, const VType* t) { map::iterator it; - if((it = old_types_.find(name)) != old_types_.end() ) - old_types_.erase(it); - new_types_[name] = t; + if((it = use_types_.find(name)) != use_types_.end() ) + use_types_.erase(it); + cur_types_[name] = t; } + inline void use_name(perm_string name, const VType* t) + { use_types_[name] = t; } + void bind_name(perm_string name, const VType*obj, Expression*val) { map::iterator it; - if((it = old_constants_.find(name)) != old_constants_.end() ) - old_constants_.erase(it); - new_constants_[name] = new const_t(obj, val); + if((it = use_constants_.find(name)) != use_constants_.end() ) + use_constants_.erase(it); + cur_constants_[name] = new const_t(obj, val); } void bind_name(perm_string name, Subprogram*obj) From e927960121d348014626fa7eade3bbfc3f2e3cf7 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 18 May 2013 17:36:29 -0700 Subject: [PATCH 05/21] Implement subprogram bodies in package bodies. --- vhdlpp/debug.cc | 11 ++++---- vhdlpp/library.cc | 24 ++++++++++++++++- vhdlpp/package.cc | 6 ++--- vhdlpp/package.h | 2 ++ vhdlpp/package_emit.cc | 8 +++--- vhdlpp/parse.y | 61 +++++++++++++++++++++++++++++++----------- vhdlpp/parse_misc.h | 2 ++ vhdlpp/scope.cc | 57 ++++++++++++++++++++++++++++----------- vhdlpp/scope.h | 31 +++++++++++++++------ vhdlpp/subprogram.cc | 38 ++++++++++++++++++++++++++ vhdlpp/subprogram.h | 6 +++++ vhdlpp/vtype.h | 5 ++++ vhdlpp/vtype_match.cc | 26 ++++++++++++++++++ 13 files changed, 224 insertions(+), 53 deletions(-) create mode 100644 vhdlpp/vtype_match.cc diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index 0a5dfc6c8..a6f9542b9 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -146,15 +146,16 @@ void Scope::dump_scope(ostream&out) const out << " signal " << cur->first.str() << ": ???" << endl; } // Dump subprograms - out << " -- Subprograms" << endl; - for (map::const_iterator cur = old_subprograms_.begin() - ; cur != old_subprograms_.end() ; ++cur) { + out << " -- Imported Subprograms" << endl; + for (map::const_iterator cur = use_subprograms_.begin() + ; cur != use_subprograms_.end() ; ++cur) { out << " subprogram " << cur->first << " is" << endl; cur->second->dump(out); out << " end subprogram " << cur->first << endl; } - for (map::const_iterator cur = new_subprograms_.begin() - ; cur != new_subprograms_.end() ; ++cur) { + out << " -- Subprograms from this scope" << endl; + for (map::const_iterator cur = cur_subprograms_.begin() + ; cur != cur_subprograms_.end() ; ++cur) { out << " subprogram " << cur->first << " is" << endl; cur->second->dump(out); out << " end subprogram " << cur->first << endl; diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index 01b5e0ee4..86c7c8ccc 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -120,7 +120,8 @@ void dump_libraries(ostream&file) /* * This function saves a package into the named library. Create the - * library if necessary. + * library if necessary. The parser uses this when it is finished with + * a package declaration. */ void library_save_package(perm_string parse_library_name, Package*pack) { @@ -139,6 +140,27 @@ void library_save_package(perm_string parse_library_name, Package*pack) pack->set_library(parse_library_name); } +/* + * The parser uses this function in the package body rule to recall + * the package that was declared earlier. + */ +Package*library_recall_package(perm_string parse_library_name, perm_string package_name) +{ + perm_string use_libname = parse_library_name.str() + ? parse_library_name + : perm_string::literal("work"); + + map::iterator lib = libraries.find(use_libname); + if (lib == libraries.end()) + return 0; + + map::iterator pkg = lib->second.packages.find(package_name); + if (pkg == lib->second.packages.end()) + return 0; + + return pkg->second; +} + static void import_library_name(const YYLTYPE&loc, perm_string name) { if (library_dir[name] != string()) diff --git a/vhdlpp/package.cc b/vhdlpp/package.cc index aea43c1bf..44f9ca3bc 100644 --- a/vhdlpp/package.cc +++ b/vhdlpp/package.cc @@ -46,8 +46,6 @@ void Package::set_library(perm_string lname) */ void Package::write_to_stream(ostream&fd) const { - ivl_assert(*this, new_subprograms_.size() == 0); - fd << "package " << name_ << " is" << endl; // Start out pre-declaring all the type definitions so that @@ -104,8 +102,8 @@ void Package::write_to_stream(ostream&fd) const fd << ";" << endl; } - for (map::const_iterator cur = old_subprograms_.begin() - ; cur != old_subprograms_.end() ; ++cur) { + for (map::const_iterator cur = cur_subprograms_.begin() + ; cur != cur_subprograms_.end() ; ++cur) { cur->second->write_to_stream(fd); } diff --git a/vhdlpp/package.h b/vhdlpp/package.h index 484bea53b..046708c30 100644 --- a/vhdlpp/package.h +++ b/vhdlpp/package.h @@ -36,6 +36,8 @@ class Package : public Scope, public LineInfo { perm_string name() const { return name_; } + Subprogram* recall_subprogram(perm_string name) const; + // This method writes a package header to a library file. void write_to_stream(std::ostream&fd) const; diff --git a/vhdlpp/package_emit.cc b/vhdlpp/package_emit.cc index b4b0836a2..5792cd728 100644 --- a/vhdlpp/package_emit.cc +++ b/vhdlpp/package_emit.cc @@ -26,11 +26,9 @@ using namespace std; int Package::emit_package(ostream&fd) const { - ivl_assert(*this, new_subprograms_.empty()); - // Don't emit the package if there is nothing in it that SV // cares about. - if (cur_types_.empty() && cur_constants_.empty() && old_subprograms_.empty()) + if (cur_types_.empty() && cur_constants_.empty() && cur_subprograms_.empty()) return 0; // If this package was imported from a library, then do not @@ -67,8 +65,8 @@ int Package::emit_package(ostream&fd) const fd << ";" << endl; } - for (map::const_iterator cur = old_subprograms_.begin() - ; cur != old_subprograms_.end() ; ++ cur) { + for (map::const_iterator cur = cur_subprograms_.begin() + ; cur != cur_subprograms_.end() ; ++ cur) { errors += cur->second->emit_package(fd); } diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index e15c199ae..cc278f3ab 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -322,11 +322,12 @@ static list* record_elements(list*names, %type element_declaration element_declaration_list %type architecture_body_start package_declaration_start +%type package_body_start %type identifier_opt identifier_colon_opt logical_name suffix %type logical_name_list identifier_list %type enumeration_literal_list enumeration_literal -%type sequence_of_statements if_statement_else +%type if_statement_else sequence_of_statements subprogram_statement_part %type sequential_statement if_statement signal_assignment_statement %type case_statement procedure_call procedure_call_statement %type loop_statement variable_assignment_statement @@ -1613,20 +1614,40 @@ package_declarative_part_opt | ; -package_body - : K_package K_body IDENTIFIER K_is +package_body /* IEEE 1076-2008 P4.8 */ + : package_body_start K_is package_body_declarative_part_opt K_end K_package_opt identifier_opt ';' - { sorrymsg(@1, "Package body is not yet supported.\n"); - delete[] $3; - if($8) delete[] $8; + { perm_string name = lex_strings.make($1); + if ($6 && name != $6) + errormsg(@6, "Package name (%s) doesn't match closing name (%s).\n", $1, $6); + delete[] $1; + if($6) delete[]$6; + pop_scope(); } - | K_package K_body IDENTIFIER K_is - error - K_end K_package_opt identifier_opt ';' - { errormsg(@1, "Errors in package body.\n"); + | package_body_start K_is error K_end K_package_opt identifier_opt ';' + { errormsg(@1, "Errors in package %s body.\n", $1); yyerrok; + pop_scope(); + } + ; + +/* + * This is a portion of the package_body rule that we factor out so + * that we can use this rule to start the scope. + */ +package_body_start + : K_package K_body IDENTIFIER + { perm_string name = lex_strings.make($3); + push_scope(); + Package*pkg = library_recall_package(parse_library_name, name); + if (pkg != 0) { + active_scope->set_package_header(pkg); + } else { + errormsg(@1, "Package body for %s has no matching header.\n", $3); + } + $$ = $3; } ; @@ -2065,14 +2086,24 @@ signal_assignment_statement } ; + /* This is a function/task body. This may have a matching subprogram + declaration, and if so it will be in the active scope. */ + subprogram_body /* IEEE 1076-2008 P4.3 */ : subprogram_specification K_is subprogram_declarative_part K_begin subprogram_statement_part K_end subprogram_kind_opt identifier_opt ';' - { sorrymsg(@2, "Subprogram bodies not supported.\n"); - if ($1) delete $1; - if ($8) delete[]$8; + { Subprogram*prog = $1; + Subprogram*tmp = active_scope->recall_subprogram(prog->name()); + if (tmp && prog->compare_specification(tmp)) { + delete prog; + prog = tmp; + } else if (tmp) { + errormsg(@1, "Subprogram specification for %s doesn't match specification in package header.\n", prog->name().str()); + } + prog->set_program_body($5); + active_scope->bind_name(prog->name(), prog); } | subprogram_specification K_is @@ -2122,8 +2153,8 @@ subprogram_specification sequential_statement. Also handle the special case of an empty list here. */ subprogram_statement_part - : sequence_of_statements - | + : sequence_of_statements { $$ = $1; } + | { $$ = 0; } ; subtype_declaration diff --git a/vhdlpp/parse_misc.h b/vhdlpp/parse_misc.h index da1fd0135..d54a648f9 100644 --- a/vhdlpp/parse_misc.h +++ b/vhdlpp/parse_misc.h @@ -57,6 +57,8 @@ extern const VType* parse_type_by_name(perm_string name); */ extern void library_save_package(perm_string library_parse_name, Package*pack); +extern Package*library_recall_package(perm_string library_parse_name, perm_string name); + extern void library_import(const YYLTYPE&loc, const std::list*names); extern void library_use(const YYLTYPE&loc, ActiveScope*res, const char*libname, const char*pack, const char*ident); diff --git a/vhdlpp/scope.cc b/vhdlpp/scope.cc index 33fdeb2f4..77ba7c4f6 100644 --- a/vhdlpp/scope.cc +++ b/vhdlpp/scope.cc @@ -18,9 +18,11 @@ */ # include "scope.h" +# include "package.h" # include # include # include +# include using namespace std; @@ -52,11 +54,9 @@ ScopeBase::ScopeBase(const ActiveScope&ref) ); use_types_ = ref.use_types_; cur_types_ = ref.cur_types_; - merge(ref.old_subprograms_.begin(), ref.old_subprograms_.end(), - ref.new_subprograms_.begin(), ref.new_subprograms_.end(), - insert_iterator >( - old_subprograms_, old_subprograms_.end()) - ); + + use_subprograms_ = ref.use_subprograms_; + cur_subprograms_ = ref.cur_subprograms_; } ScopeBase::~ScopeBase() @@ -76,7 +76,7 @@ void ScopeBase::cleanup() delete_all(new_components_); delete_all(cur_types_); delete_all(cur_constants_); - delete_all(new_subprograms_); + delete_all(cur_subprograms_); } const VType*ScopeBase::find_type(perm_string by_name) @@ -139,6 +139,21 @@ Variable* ScopeBase::find_variable(perm_string by_name) const } } +Subprogram* ScopeBase::find_subprogram(perm_string name) const +{ + map::const_iterator cur; + + cur = cur_subprograms_.find(name); + if (cur != cur_subprograms_.end()) + return cur->second; + + cur = use_subprograms_.find(name); + if (cur != use_subprograms_.find(name)) + return cur->second; + + return 0; +} + /* * This method is only used by the ActiveScope derived class to import * definition from another scope. @@ -158,19 +173,14 @@ void ScopeBase::do_use_from(const ScopeBase*that) old_components_[cur->first] = cur->second; } - for (map::const_iterator cur = that->old_subprograms_.begin() - ; cur != that->old_subprograms_.end() ; ++ cur) { + for (map::const_iterator cur = that->cur_subprograms_.begin() + ; cur != that->cur_subprograms_.end() ; ++ cur) { if (cur->second == 0) continue; - old_subprograms_[cur->first] = cur->second; - } - for (map::const_iterator cur = that->new_subprograms_.begin() - ; cur != that->new_subprograms_.end() ; ++ cur) { - if (cur->second == 0) - continue; - old_subprograms_[cur->first] = cur->second; + 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) @@ -184,6 +194,23 @@ void ScopeBase::do_use_from(const ScopeBase*that) } } +void ActiveScope::set_package_header(Package*pkg) +{ + assert(package_header_ == 0); + package_header_ = pkg; +} + +Subprogram* ActiveScope::recall_subprogram(perm_string name) const +{ + if (Subprogram*tmp = find_subprogram(name)) + return tmp; + + if (package_header_) + return package_header_->find_subprogram(name); + + return 0; +} + bool ActiveScope::is_vector_name(perm_string name) const { if (find_signal(name)) diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index 7c0644817..790c709c9 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -57,6 +57,7 @@ class ScopeBase { bool find_constant(perm_string by_name, const VType*&typ, Expression*&exp); Signal* find_signal(perm_string by_name) const; Variable* find_variable(perm_string by_name) const; + Subprogram* find_subprogram(perm_string by_name) const; protected: void cleanup(); @@ -100,8 +101,8 @@ class ScopeBase { std::map use_constants_; //imported constants std::map cur_constants_; //current constants - std::map old_subprograms_; //previous scopes - std::map new_subprograms_; //current scope + std::map use_subprograms_; //imported + std::map cur_subprograms_; //current void do_use_from(const ScopeBase*that); }; @@ -132,11 +133,16 @@ class Scope : public ScopeBase { class ActiveScope : public ScopeBase { public: - ActiveScope() : context_entity_(0) { } - ActiveScope(ActiveScope*par) : ScopeBase(*par), context_entity_(0) { } + ActiveScope() : package_header_(0), context_entity_(0) { } + ActiveScope(ActiveScope*par) : ScopeBase(*par), package_header_(0), context_entity_(0) { } ~ActiveScope() { } + void set_package_header(Package*); + + // Pull items from "that" scope into "this" scope as is + // defined by a "use" directive. The parser uses this method + // to implement the "use ::*" directive. void use_from(const Scope*that) { do_use_from(that); } // This function returns true if the name is a vectorable @@ -144,6 +150,11 @@ class ActiveScope : public ScopeBase { // calls and array index operations. bool is_vector_name(perm_string name) const; + // Locate the subprogram by name. The subprogram body uses + // this to locate the sobprogram declaration. Note that the + // subprogram may be in a package header. + Subprogram* recall_subprogram(perm_string name) const; + /* All bind_name function check if the given name was present * in previous scopes. If it is found, it is erased (but the pointer * is not freed), in order to implement name shadowing. The pointer @@ -188,11 +199,11 @@ class ActiveScope : public ScopeBase { cur_constants_[name] = new const_t(obj, val); } - void bind_name(perm_string name, Subprogram*obj) + inline void bind_name(perm_string name, Subprogram*obj) { map::iterator it; - if((it = old_subprograms_.find(name)) != old_subprograms_.end() ) - old_subprograms_.erase(it); - new_subprograms_[name] = obj;; + if((it = use_subprograms_.find(name)) != use_subprograms_.end() ) + use_subprograms_.erase(it); + cur_subprograms_[name] = obj;; } void bind(Entity*ent) @@ -208,6 +219,10 @@ class ActiveScope : public ScopeBase { std::map incomplete_types; private: + // If this is a package body, then there is a Package header + // already declared. + Package*package_header_; + Entity*context_entity_; }; diff --git a/vhdlpp/subprogram.cc b/vhdlpp/subprogram.cc index 3aa1fb94b..25b6deb9d 100644 --- a/vhdlpp/subprogram.cc +++ b/vhdlpp/subprogram.cc @@ -21,6 +21,7 @@ # include "subprogram.h" # include "entity.h" # include "vtype.h" +# include "ivl_assert.h" using namespace std; @@ -34,6 +35,43 @@ Subprogram::~Subprogram() { } +void Subprogram::set_program_body(list*stmt) +{ + ivl_assert(*this, statements_==0); + statements_ = stmt; +} + +bool Subprogram::compare_specification(Subprogram*that) const +{ + if (name_ != that->name_) + return false; + + if (return_type_==0) { + if (that->return_type_!=0) + return false; + } else { + if (that->return_type_==0) + return false; + + if (! return_type_->type_match(that->return_type_)) + return false; + } + + if (ports_==0) { + if (that->ports_!=0) + return false; + + } else { + if (that->ports_==0) + return false; + + if (ports_->size() != that->ports_->size()) + return false; + } + + return true; +} + void Subprogram::write_to_stream(ostream&fd) const { fd << " function " << name_ << "("; diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h index 7ec691d32..ea12e3934 100644 --- a/vhdlpp/subprogram.h +++ b/vhdlpp/subprogram.h @@ -38,6 +38,12 @@ class Subprogram : public LineInfo { inline const perm_string&name() const { return name_; } + void set_program_body(std::list*statements); + + // Return true if the specification (name, types, ports) + // matches this subprogram and that subprogram. + bool compare_specification(Subprogram*that) const; + // Emit a definition as it would show up in a package. int emit_package(std::ostream&fd) const; diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index 3edbe44a2..9d185ad0e 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -45,6 +45,11 @@ class VType { VType() { } virtual ~VType() =0; + // This virtual method returns true if that is equivalent to + // this type. This method is used for example to compare + // function prototypes. + virtual bool type_match(const VType*that) const; + // This virtual method writes a VHDL-accurate representation // of this type to the designated stream. This is used for // writing parsed types to library files. diff --git a/vhdlpp/vtype_match.cc b/vhdlpp/vtype_match.cc new file mode 100644 index 000000000..e0559d24d --- /dev/null +++ b/vhdlpp/vtype_match.cc @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * 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. + */ + +# include "vtype.h" + +bool VType::type_match(const VType*that) const +{ + return this == that; +} From 164b5f9348eadb31ddefb50c430dbc482dc1a73a Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 19 May 2013 17:23:12 -0700 Subject: [PATCH 06/21] Fix SV emit of ForLoopStatement and ReturnStmt. --- vhdlpp/sequential.h | 4 +++- vhdlpp/sequential_emit.cc | 27 +++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/vhdlpp/sequential.h b/vhdlpp/sequential.h index bd553fef6..5e12ec503 100644 --- a/vhdlpp/sequential.h +++ b/vhdlpp/sequential.h @@ -1,7 +1,8 @@ #ifndef __sequential_H #define __sequential_H /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -116,6 +117,7 @@ class ReturnStmt : public SequentialStmt { ~ReturnStmt(); public: + int emit(ostream&out, Entity*entity, Architecture*arc); void dump(ostream&out, int indent) const; private: diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index a7e8e40f4..e3c0fab71 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -1,5 +1,6 @@ /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -82,6 +83,14 @@ int IfSequential::Elsif::statement_emit(ostream&out, Entity*ent, Architecture*ar return errors; } +int ReturnStmt::emit(ostream&out, Entity*ent, Architecture*arc) +{ + int errors = 0; + out << "return "; + errors += val_->emit(out, ent, arc); + out << ";" << endl; + return errors; +} int SignalSeqAssignment::emit(ostream&out, Entity*ent, Architecture*arc) { @@ -203,13 +212,23 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, Architecture*arc) ivl_assert(*this, start_rc); ivl_assert(*this, finish_rc); - if (range_->is_downto() && start_val < finish_val) { - out << "begin /* Degenerate loop at " << get_fileline() << " */ end" << endl; + if (! range_->is_downto()) { + int64_t tmp = start_val; + start_val = finish_val; + finish_val = tmp; + } + + if (range_->is_downto() && (start_val < finish_val)) { + out << "begin /* Degenerate loop at " << get_fileline() + << ": " << start_val + << " downto " << finish_val << " */ end" << endl; return errors; } if (!range_->is_downto() && start_val > finish_val) { - out << "begin /* Degenerate loop at " << get_fileline() << " */ end" << endl; + out << "begin /* Degenerate loop at " << get_fileline() + << ": " << start_val + << " to " << finish_val << " */ end" << endl; return errors; } From dca6171f5f06c4e5772e5bacf9c1a5f31d4781d4 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 19 May 2013 18:36:29 -0700 Subject: [PATCH 07/21] SV emit function ports in package subprograms. --- vhdlpp/parse.y | 11 +++++++++++ vhdlpp/subprogram_emit.cc | 25 ++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index cc278f3ab..09c8e5f78 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -182,6 +182,16 @@ static list* record_elements(list*names, return res; } +static void touchup_interface_for_functions(std::list*ports) +{ + for (list::iterator cur = ports->begin() + ; cur != ports->end() ; ++cur) { + InterfacePort*curp = *cur; + if (curp->mode == PORT_NONE) + curp->mode = PORT_IN; + } +} + %} @@ -1152,6 +1162,7 @@ function_specification /* IEEE 1076-2008 P4.2.1 */ { perm_string type_name = lex_strings.make($7); perm_string name = lex_strings.make($2); const VType*type_mark = active_scope->find_type(type_name); + touchup_interface_for_functions($4); Subprogram*tmp = new Subprogram(name, $4, type_mark); FILE_NAME(tmp,@1); delete[]$2; diff --git a/vhdlpp/subprogram_emit.cc b/vhdlpp/subprogram_emit.cc index e70351a4c..efd586bd0 100644 --- a/vhdlpp/subprogram_emit.cc +++ b/vhdlpp/subprogram_emit.cc @@ -33,11 +33,34 @@ int Subprogram::emit_package(ostream&fd) const fd << "function "; return_type_->emit_def(fd); fd << " " << name_; - fd << ";" << endl; + fd << "("; } else { fd << "task " << name_ << ";" << endl; } + for (list::const_iterator cur = ports_->begin() + ; cur != ports_->end() ; ++cur) { + if (cur != ports_->begin()) + fd << ", "; + InterfacePort*curp = *cur; + switch (curp->mode) { + case PORT_IN: + fd << "input "; + break; + case PORT_OUT: + fd << "output "; + break; + case PORT_NONE: + fd << "inout /* PORT_NONE? */ "; + break; + } + + errors += curp->type->emit_def(fd); + fd << " \\" << curp->name << " "; + } + + fd << ");" << endl; + if (statements_) { for (list::const_iterator cur = statements_->begin() ; cur != statements_->end() ; ++cur) { From 1b178d56b7057b3416e30e19e823b29c6b1bc455 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 23 May 2013 19:59:57 -0700 Subject: [PATCH 08/21] Add support for SystemVerilog return statements. --- Statement.cc | 12 ++++++++- Statement.h | 13 +++++++++ elaborate.cc | 63 ++++++++++++++++++++++++++++++++++++++++++++ parse.y | 10 ++++--- pform_dump.cc | 9 ++++++- tgt-stub/statement.c | 12 ++++++++- 6 files changed, 112 insertions(+), 7 deletions(-) diff --git a/Statement.cc b/Statement.cc index 79d63fb63..a5e2677bd 100644 --- a/Statement.cc +++ b/Statement.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2008,2010,2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2008,2010,2012-2013 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -329,6 +329,16 @@ PRepeat::~PRepeat() delete statement_; } +PReturn::PReturn(PExpr*e) +: expr_(e) +{ +} + +PReturn::~PReturn() +{ + delete expr_; +} + PTrigger::PTrigger(const pform_name_t&e) : event_(e) { diff --git a/Statement.h b/Statement.h index 43f299443..3091490e6 100644 --- a/Statement.h +++ b/Statement.h @@ -462,6 +462,19 @@ class PRelease : public Statement { PExpr*lval_; }; +class PReturn : public Statement { + + public: + explicit PReturn(PExpr*e); + ~PReturn(); + + NetProc* elaborate(Design*des, NetScope*scope) const; + virtual void dump(std::ostream&out, unsigned ind) const; + + private: + PExpr*expr_; +}; + /* * The PTrigger statement sends a trigger to a named event. Take the * name here. diff --git a/elaborate.cc b/elaborate.cc index 29f1cca24..6af548058 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -4443,6 +4443,69 @@ NetProc* PRepeat::elaborate(Design*des, NetScope*scope) const return proc; } +NetProc* PReturn::elaborate(Design*des, NetScope*scope) const +{ + NetScope*target = scope; + for (;;) { + if (target == 0) { + cerr << get_fileline() << ": error: " + << "Return statement is not in a function." << endl; + des->errors += 1; + return 0; + } + + if (target->type() == NetScope::FUNC) + break; + + if (target->type() == NetScope::TASK) { + cerr << get_fileline() << ": error: " + << "Cannot \"return\" from tasks." << endl; + des->errors += 1; + return 0; + } + + if (target->type()==NetScope::BEGIN_END) { + target = target->parent(); + continue; + } + + cerr << get_fileline() << ": error: " + << "Cannot \"return\" from this scope: " << scope_path(target) << endl; + des->errors += 1; + return 0; + } + + // We don't yet support void functions, so require an + // expression for the return statement. + if (expr_ == 0) { + cerr << get_fileline() << ": error: " + << "Return from " << scope_path(target) + << " requires a return value expression." << endl; + des->errors += 1; + return 0; + } + + NetNet*res = target->find_signal(target->basename()); + ivl_variable_type_t lv_type = res->data_type(); + unsigned long wid = res->vector_width(); + NetAssign_*lv = new NetAssign_(res); + + NetExpr*val = elaborate_rval_expr(des, scope, lv_type, wid, expr_); + + NetBlock*proc = new NetBlock(NetBlock::SEQU, 0); + proc->set_line( *this ); + + NetAssign*assn = new NetAssign(lv, val); + assn->set_line( *this ); + proc->append(assn); + + NetDisable*disa = new NetDisable(target); + disa->set_line( *this ); + proc->append( disa ); + + return proc; +} + /* * A task definition is elaborated by elaborating the statement that * it contains, and connecting its ports to NetNet objects. The diff --git a/parse.y b/parse.y index 20e62f77e..6ace0aa1e 100644 --- a/parse.y +++ b/parse.y @@ -1229,12 +1229,14 @@ jump_statement /* IEEE1800-2005: A.6.5 */ $$ = 0; } | K_return ';' - { yyerror(@1, "sorry: return statements not supported."); - $$ = 0; + { PReturn*tmp = new PReturn(0); + FILE_NAME(tmp, @1); + $$ = tmp; } | K_return expression ';' - { yyerror(@1, "sorry: return statements not supported."); - $$ = 0; + { PReturn*tmp = new PReturn($2); + FILE_NAME(tmp, @1); + $$ = tmp; } ; diff --git a/pform_dump.cc b/pform_dump.cc index feb274697..dafa6fd12 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -928,6 +928,13 @@ void PRepeat::dump(ostream&out, unsigned ind) const statement_->dump(out, ind+3); } +void PReturn::dump(ostream&fd, unsigned ind) const +{ + fd << setw(ind) << "" << "return ("; + if (expr_) fd << *expr_; + fd << ")" << endl; +} + void PTask::dump(ostream&out, unsigned ind) const { out << setw(ind) << "" << "task "; diff --git a/tgt-stub/statement.c b/tgt-stub/statement.c index ea020b6f0..eed16f055 100644 --- a/tgt-stub/statement.c +++ b/tgt-stub/statement.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2013 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -153,6 +153,12 @@ static void show_stmt_delayx(ivl_statement_t net, unsigned ind) show_statement(ivl_stmt_sub_stmt(net), ind+2); } +static void show_stmt_disable(ivl_statement_t net, unsigned ind) +{ + ivl_scope_t scope = ivl_stmt_call(net); + fprintf(out, "%*sdisable %s\n", ind, "", ivl_scope_basename(scope)); +} + static void show_stmt_force(ivl_statement_t net, unsigned ind) { unsigned idx; @@ -378,6 +384,10 @@ void show_statement(ivl_statement_t net, unsigned ind) show_stmt_delayx(net, ind); break; + case IVL_ST_DISABLE: + show_stmt_disable(net, ind); + break; + case IVL_ST_FORCE: show_stmt_force(net, ind); break; From bc77a1905927ba9ef11e5b31bd861ba1bd619852 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 26 May 2013 18:16:59 -0700 Subject: [PATCH 09/21] Use $ivl_unsigned to implement VHDL to_unsigned function. The VHDL to_unsigned function with to arguments is best handled in the ivl elaborator, so have it generate an $ivlh_to_unsigned function call in the vhdlpp code, and implement it in the ivl core. Also, implement the 'length attribute as a $bits() call for similar reasons. --- elab_expr.cc | 42 +++++++++++++++++++++++++++++++++++++++ vhdlpp/expression_emit.cc | 42 ++++++++++++++++++++++++++------------- 2 files changed, 70 insertions(+), 14 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index d82b82b11..d14602f09 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -933,6 +933,35 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope, { perm_string name = peek_tail_name(path_); + if (name=="$ivlh_to_unsigned") { + ivl_assert(*this, parms_.size() == 2); + // The Icarus Verilog specific $ivl_unsigned() system + // task takes a second argument which is the output + // size. This can be an arbitrary constant function. + PExpr*pexpr = parms_[1]; + if (pexpr == 0) { + cerr << get_fileline() << ": error: " + << "Missing $ivlh_to_unsigned width." << endl; + return 0; + } + + NetExpr*nexpr = elab_and_eval(des, scope, pexpr, -1, true); + if (nexpr == 0) { + cerr << get_fileline() << ": error: " + << "Unable to evaluate " << name + << " width argument: " << *pexpr << endl; + return 0; + } + + long value = 0; + bool rc = eval_as_long(value, nexpr); + ivl_assert(*this, rc && value>=0); + + expr_width_ = value; + signed_flag_= false; + return expr_width_; + } + if (name=="$signed" || name=="$unsigned") { PExpr*expr = parms_[0]; if (expr == 0) @@ -1228,6 +1257,19 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, { perm_string name = peek_tail_name(path_); + /* Catch the special case that the system function is the + $ivl_unsigned function. In this case the second argument is + the size of the expression, but should already be accounted + for so treat this very much like the $unsigned() function. */ + if (name=="$ivlh_to_unsigned") { + ivl_assert(*this, parms_.size()==2); + + PExpr*expr = parms_[0]; + ivl_assert(*this, expr); + NetExpr*sub = expr->elaborate_expr(des, scope, expr_width_, flags); + return cast_to_width_(sub, expr_wid); + } + /* Catch the special case that the system function is the $signed function. Its argument will be evaluated as a self-determined expression. */ diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 2c1b43114..d4fa884e1 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -1,5 +1,6 @@ /* - * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -24,6 +25,7 @@ # include # include # include +# include # include "ivl_assert.h" # include @@ -278,16 +280,14 @@ int ExpAttribute::emit(ostream&out, Entity*ent, Architecture*arc) the down to a literal integer at compile time, and all it needs is the type of the base expression. (The base expression doesn't even need to be evaluated.) */ - if (name_ == "length") { - int64_t val; - bool rc = evaluate(ent, arc, val); - out << val; - if (rc) - return errors; - else - return errors + 1; + if (name_=="length") { + out << "$bits("; + errors += base_->emit(out, ent, arc); + out << ")"; + return errors; } + out << "$ivl_attribute("; errors += base_->emit(out, ent, arc); out << ", \"" << name_ << "\")"; @@ -539,13 +539,12 @@ int ExpFunc::emit(ostream&out, Entity*ent, Architecture*arc) out << ")"; } else if (name_ == "to_unsigned" && argv_.size() == 2) { - int64_t use_size; - bool rc = argv_[1]->evaluate(ent, arc, use_size); - ivl_assert(*this, rc); - out << "$unsigned(" << use_size << "'("; + out << "$ivlh_to_unsigned("; errors += argv_[0]->emit(out, ent, arc); - out << "))"; + out << ", "; + errors += argv_[1]->emit(out, ent, arc); + out << ")"; } else if (name_ == "conv_std_logic_vector" && argv_.size() == 2) { int64_t use_size; @@ -727,6 +726,18 @@ int ExpString::emit_as_array_(ostream& out, Entity*, Architecture*, const VTypeA const VTypePrimitive*etype = dynamic_cast (arr->element_type()); assert(etype); + // Detect the special case that this is an array of + // CHARACTER. In this case, emit at a Verilog string. + if (etype->type()==VTypePrimitive::CHARACTER) { + vector tmp (value_.size() + 3); + tmp[0] = '"'; + memcpy(&tmp[1], &value_[0], value_.size()); + tmp[value_.size()+1] = '"'; + tmp[value_.size()+2] = 0; + out << &tmp[0]; + return errors; + } + assert(etype->type() != VTypePrimitive::INTEGER); out << value_.size() << "'b"; for (size_t idx = 0 ; idx < value_.size() ; idx += 1) { @@ -742,6 +753,9 @@ int ExpString::emit_as_array_(ostream& out, Entity*, Architecture*, const VTypeA out << "z"; break; default: + cerr << get_fileline() << ": internal error: " + << "Don't know how to handle bit " << value_[idx] + << " with etype==" << etype->type() << endl; assert(etype->type() == VTypePrimitive::STDLOGIC); out << "x"; break; From 096e53dea47100a62be86ae193a1139862839937 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 31 May 2013 19:37:41 -0700 Subject: [PATCH 10/21] Don't crash if function is not found. --- elab_expr.cc | 6 ++++++ symbol_search.cc | 2 ++ 2 files changed, 8 insertions(+) diff --git a/elab_expr.cc b/elab_expr.cc index d14602f09..673afb19b 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -2054,6 +2054,12 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, perm_string method_name = peek_tail_name(use_path); use_path.pop_back(); + // If there is no object to the left of the method name, then + // give up on the idea of looking for an object method. + if (use_path.empty()) { + return 0; + } + NetNet *net = 0; const NetExpr *par; NetEvent *eve; diff --git a/symbol_search.cc b/symbol_search.cc index 3302bff5a..1b26bb22a 100644 --- a/symbol_search.cc +++ b/symbol_search.cc @@ -65,6 +65,8 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, assert(scope); bool prefix_scope = false; bool recurse_flag = false; + + ivl_assert(*li, ! path.empty()); name_component_t path_tail = path.back(); path.pop_back(); From bfe3998eaa3c63a52df40cfc3c7d32290b7e2458 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 31 May 2013 19:52:11 -0700 Subject: [PATCH 11/21] Lexor detects that excaped identifiers may be package names. --- lexor.lex | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lexor.lex b/lexor.lex index 2a362be39..2408cdf7a 100644 --- a/lexor.lex +++ b/lexor.lex @@ -367,6 +367,13 @@ TU [munpf] \\[^ \t\b\f\r\n]+ { yylval.text = strdupnew(yytext+1); + if (gn_system_verilog()) { + if (PPackage*pkg = pform_test_package_identifier(yylval.text)) { + delete[]yylval.text; + yylval.package = pkg; + return PACKAGE_IDENTIFIER; + } + } if (gn_system_verilog()) { if (data_type_t*type = pform_test_type_identifier(yylval.text)) { delete[]yylval.text; From 5c00b96127ed17383d8390649836f6cbc1ff0c27 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 1 Jun 2013 14:39:43 -0700 Subject: [PATCH 12/21] Handle constant functions from other scopes, i.e. packages. --- elab_expr.cc | 17 +++++++++++++++++ net_func_eval.cc | 11 +++++++++++ 2 files changed, 28 insertions(+) diff --git a/elab_expr.cc b/elab_expr.cc index 673afb19b..13d4d6459 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1923,6 +1923,23 @@ NetExpr* PECallFunction::elaborate_base_(Design*des, NetScope*scope, NetScope*ds bool need_const = NEED_CONST & flags; + // If this is a constant expression, it is possible that we + // are being elaborated before the function definition. If + // that's the case, try to elaborate the function as a const + // function. + if (need_const && ! def->proc()) { + if (debug_elaborate) { + cerr << get_fileline() << ": PECallFunction::elaborate_base_: " + << "Try to elaborate " << scope_path(dscope) + << " as constant function." << endl; + } + dscope->set_elab_stage(2); + dscope->need_const_func(true); + const PFunction*pfunc = dscope->func_pform(); + ivl_assert(*this, pfunc); + pfunc->elaborate(des, dscope); + } + unsigned parms_count = parms_.size(); if ((parms_count == 1) && (parms_[0] == 0)) parms_count = 0; diff --git a/net_func_eval.cc b/net_func_eval.cc index f5bef42c4..db2dd2260 100644 --- a/net_func_eval.cc +++ b/net_func_eval.cc @@ -87,11 +87,22 @@ NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vectorevaluate_function_find_locals(loc, context_map); + if (debug_eval_tree && statement_==0) { + cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: " + << "Function " << scope_path(scope_) + << " has no statement?" << endl; + } + // Perform the evaluation. Note that if there were errors // when compiling the function definition, we may not have // a valid statement. bool flag = statement_ && statement_->evaluate_function(loc, context_map); + if (debug_eval_tree && !flag) { + cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: " + << "Cannot evaluate " << scope_path(scope_) << "." << endl; + } + // Extract the result... ptr = context_map.find(scope_->basename()); NetExpr*res = ptr->second.value; From bcaa6accec8890ff199a1e16f741a51027e2930e Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 2 Jun 2013 16:54:31 -0700 Subject: [PATCH 13/21] Fix evaluation wrong expression for const >= expressions. --- eval_tree.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eval_tree.cc b/eval_tree.cc index 1fc452bfe..6e9eb73c2 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -480,7 +480,7 @@ NetEConst* NetEBComp::eval_gteq_(const NetExpr*le, const NetExpr*re) const if (le->expr_type() == IVL_VT_REAL || re->expr_type() == IVL_VT_REAL) return eval_leeq_real_(re, le, true); - const NetEConst*l = dynamic_cast(left_); + const NetEConst*l = dynamic_cast(le); if (l == 0) return 0; verinum lv = l->value(); From af304fea65f943f6b0fd1d08cc29c7e37ef79ff7 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 2 Jun 2013 16:56:46 -0700 Subject: [PATCH 14/21] Fix repeated use of disabled const functions. If constant functions are exited by a return/disable, fix the leaked "disable" flag that causes blocks in the next try at the function to not work. There are also a lot of debug messages added to help find this and similar problems. --- elab_sig.cc | 14 ++++++++++ net_func_eval.cc | 70 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 72 insertions(+), 12 deletions(-) diff --git a/elab_sig.cc b/elab_sig.cc index 35e867426..8809d1d24 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -964,6 +964,10 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const vector plist, nlist; /* If they exist get the port definition MSB and LSB */ if (port_set_ && !port_.empty()) { + if (debug_elaborate) { + cerr << get_fileline() << ": PWire::elaborate_sig: " + << "Evaluate ranges for port " << basename() << endl; + } bad_range |= evaluate_ranges(des, scope, plist, port_); nlist = plist; /* An implicit port can have a range so note that here. */ @@ -974,10 +978,20 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const /* If they exist get the net/etc. definition MSB and LSB */ if (net_set_ && !net_.empty() && !bad_range) { nlist.clear(); + if (debug_elaborate) { + cerr << get_fileline() << ": PWire::elaborate_sig: " + << "Evaluate ranges for net " << basename() << endl; + } bad_range |= evaluate_ranges(des, scope, nlist, net_); } assert(net_set_ || net_.empty()); + if (debug_elaborate) { + cerr << get_fileline() << ": PWire::elaborate_sig: " + << "Calculated ranges for " << basename() + << ". Now check for consistency." << endl; + } + /* If we find errors here, then give up on this signal. */ if (bad_range) return 0; diff --git a/net_func_eval.cc b/net_func_eval.cc index db2dd2260..30534c917 100644 --- a/net_func_eval.cc +++ b/net_func_eval.cc @@ -60,7 +60,7 @@ NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vectorcontext_map; if (debug_eval_tree) { - cerr << loc.get_fileline() << ": debug: " + cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: " << "Evaluate function " << scope_->basename() << endl; } @@ -78,7 +78,7 @@ NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vector"; + cerr << endl; + } return res; + } + + if (debug_eval_tree) { + cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: " + << "Evaluation failed." << endl; + } delete res; return 0; @@ -256,9 +279,8 @@ bool NetAssign::eval_func_lval_(const LineInfo&loc, delete old_lval; if (debug_eval_tree) { - cerr << get_fileline() << ": debug: " - << "NetAssign::evaluate_function: " << lval->name() - << " = " << *rval_result << endl; + cerr << get_fileline() << ": NetAssign::evaluate_function: " + << lval->name() << " = " << *rval_result << endl; } if (ptr->second.nwords > 0) @@ -326,6 +348,11 @@ bool NetBlock::evaluate_function(const LineInfo&loc, if (disable == subscope_) disable = 0; + if (debug_eval_tree) { + cerr << get_fileline() << ": NetBlock::evaluate_function: " + << "flag=" << (flag?"true":"false") << endl; + } + return flag; } @@ -448,8 +475,13 @@ bool NetCondit::evaluate_function(const LineInfo&loc, map&context_map) const { NetExpr*cond = expr_->evaluate_function(loc, context_map); - if (cond == 0) + if (cond == 0) { + if (debug_eval_tree) { + cerr << get_fileline() << ": NetCondit::evaluate_function: " + << "Unable to evaluate condition (" << *expr_ <<")" << endl; + } return false; + } NetEConst*cond_const = dynamic_cast (cond); ivl_assert(loc, cond_const); @@ -457,18 +489,32 @@ bool NetCondit::evaluate_function(const LineInfo&loc, long val = cond_const->value().as_long(); delete cond; + bool flag; + if (val) // The condition is true, so evaluate the if clause - return (if_ == 0) || if_->evaluate_function(loc, context_map); + flag = (if_ == 0) || if_->evaluate_function(loc, context_map); else // The condition is false, so evaluate the else clause - return (else_ == 0) || else_->evaluate_function(loc, context_map); + flag = (else_ == 0) || else_->evaluate_function(loc, context_map); + + if (debug_eval_tree) { + cerr << get_fileline() << ": NetCondit::evaluate_function: " + << "Finished, flag=" << (flag?"true":"false") << endl; + } + return flag; } bool NetDisable::evaluate_function(const LineInfo&, map&) const { disable = target_; + + if (debug_eval_tree) { + cerr << get_fileline() << ": NetDisable::evaluate_function: " + << "disable " << scope_path(disable) << endl; + } + return true; } @@ -541,7 +587,7 @@ bool NetWhile::evaluate_function(const LineInfo&loc, bool flag = true; if (debug_eval_tree) { - cerr << get_fileline() << ": debug: NetWhile::evaluate_function: " + cerr << get_fileline() << ": NetWhile::evaluate_function: " << "Start loop" << endl; } @@ -572,8 +618,8 @@ bool NetWhile::evaluate_function(const LineInfo&loc, } if (debug_eval_tree) { - cerr << get_fileline() << ": debug: NetWhile::evaluate_function: " - << "Done loop" << endl; + cerr << get_fileline() << ": NetWhile::evaluate_function: " + << "Done loop, flag=" << (flag?"true":"false") << endl; } return flag; From 3446455055e75b228a1092e2141875876b85258b Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 5 Jun 2013 19:28:51 -0700 Subject: [PATCH 15/21] Support compile-time evaluation of named blocks. --- elaborate.cc | 8 ----- net_func_eval.cc | 91 +++++++++++++++++++++++++++++++++++++----------- netlist.h | 3 +- 3 files changed, 73 insertions(+), 29 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index 6af548058..07b70aa71 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -2793,14 +2793,6 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const if (nscope->calls_sys_task()) scope->calls_sys_task(true); - if (!wires.empty()) { - if (scope->need_const_func()) { - cerr << get_fileline() << ": sorry: Block variables inside " - "a constant function are not yet supported." << endl; - } - scope->is_const_func(false); - } - cur->set_line(*this); return cur; } diff --git a/net_func_eval.cc b/net_func_eval.cc index 30534c917..3777328d6 100644 --- a/net_func_eval.cc +++ b/net_func_eval.cc @@ -215,9 +215,15 @@ bool NetAssign::eval_func_lval_(const LineInfo&loc, map::iterator ptr = context_map.find(lval->name()); ivl_assert(*this, ptr != context_map.end()); + LocalVar*var = & ptr->second; + while (var->nwords == -1) { + assert(var->ref); + var = var->ref; + } + NetExpr*old_lval; - unsigned word = 0; - if (ptr->second.nwords > 0) { + int word = 0; + if (var->nwords > 0) { NetExpr*word_result = lval->word()->evaluate_function(loc, context_map); if (word_result == 0) { delete rval_result; @@ -232,12 +238,13 @@ bool NetAssign::eval_func_lval_(const LineInfo&loc, word = word_const->value().as_long(); - if (word >= ptr->second.nwords) + if (word >= var->nwords) return true; - old_lval = ptr->second.array[word]; + old_lval = var->array[word]; } else { - old_lval = ptr->second.value; + assert(var->nwords == 0); + old_lval = var->value; } if (const NetExpr*base_expr = lval->get_base()) { @@ -283,10 +290,12 @@ bool NetAssign::eval_func_lval_(const LineInfo&loc, << lval->name() << " = " << *rval_result << endl; } - if (ptr->second.nwords > 0) - ptr->second.array[word] = rval_result; - else - ptr->second.value = rval_result; + if (var->nwords > 0) { + var->array[word] = rval_result; + } else { + assert(var->nwords == 0); + var->value = rval_result; + } return true; } @@ -336,23 +345,58 @@ bool NetAssign::evaluate_function(const LineInfo&loc, bool NetBlock::evaluate_function(const LineInfo&loc, map&context_map) const { + if (last_ == 0) return true; + + // If we need to make a local scope, then this context map + // will be filled in and used for statements within this block. + maplocal_context_map; + bool use_local_context_map = false; + + if (subscope_!=0) { + // First, copy the containing scope symbols into the new + // scope as references. + for (map::iterator cur = context_map.begin() + ; cur != context_map.end() ; ++cur) { + LocalVar&cur_var = local_context_map[cur->first]; + cur_var.nwords = -1; + if (cur->second.nwords == -1) + cur_var.ref = cur->second.ref; + else + cur_var.ref = &cur->second; + } + + // Now collect the new locals. + subscope_->evaluate_function_find_locals(loc, local_context_map); + use_local_context_map = true; + } + + // Now use the local context map if there is any local + // context, or the containing context map. + map&use_context_map = use_local_context_map? local_context_map : context_map; + bool flag = true; NetProc*cur = last_; - if (cur == 0) return true; - do { cur = cur->next_; - bool cur_flag = cur->evaluate_function(loc, context_map); + if (debug_eval_tree) { + cerr << get_fileline() << ": NetBlock::evaluate_function: " + << "Execute statement (" << typeid(*cur).name() + << ") at " << cur->get_fileline() << "." << endl; + } + + bool cur_flag = cur->evaluate_function(loc, use_context_map); flag = flag && cur_flag; } while (cur != last_ && !disable); - if (disable == subscope_) disable = 0; - if (debug_eval_tree) { cerr << get_fileline() << ": NetBlock::evaluate_function: " - << "flag=" << (flag?"true":"false") << endl; + << "subscope_=" << subscope_ + << ", disable=" << disable + << ", flag=" << (flag?"true":"false") << endl; } + if (disable == subscope_) disable = 0; + return flag; } @@ -731,8 +775,15 @@ NetExpr* NetESignal::evaluate_function(const LineInfo&loc, return 0; } + // Follow indirect references to the actual variable. + LocalVar*var = & ptr->second; + while (var->nwords == -1) { + assert(var->ref); + var = var->ref; + } + NetExpr*value = 0; - if (ptr->second.nwords > 0) { + if (var->nwords > 0) { ivl_assert(loc, word_); NetExpr*word_result = word_->evaluate_function(loc, context_map); if (word_result == 0) @@ -741,12 +792,12 @@ NetExpr* NetESignal::evaluate_function(const LineInfo&loc, NetEConst*word_const = dynamic_cast(word_result); ivl_assert(loc, word_const); - unsigned word = word_const->value().as_long(); + int word = word_const->value().as_long(); - if (word_const->value().is_defined() && (word < ptr->second.nwords)) - value = ptr->second.array[word]; + if (word_const->value().is_defined() && (word < var->nwords)) + value = var->array[word]; } else { - value = ptr->second.value; + value = var->value; } if (value == 0) { diff --git a/netlist.h b/netlist.h index 936c94d14..39543e1e3 100644 --- a/netlist.h +++ b/netlist.h @@ -760,10 +760,11 @@ class NetNet : public NetObj, public PortType { * evaluating constant user functions. */ struct LocalVar { - unsigned nwords; // zero for a simple variable + int nwords; // zero for a simple variable, -1 for reference union { NetExpr* value; // a simple variable NetExpr** array; // an array variable + LocalVar* ref; // A reference to a previous scope }; }; From 0fcd2d9db69433f71b9d5855b50cec6e5b43600e Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 5 Jun 2013 20:39:04 -0700 Subject: [PATCH 16/21] Handle rising_edge and falling_edge functions. --- vhdlpp/architec_elaborate.cc | 49 ++++++++++++++++++++++++++++++++++-- vhdlpp/expression.h | 4 +++ vhdlpp/expression_emit.cc | 10 ++++++++ 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index e7308f96e..3ffc8c6da 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -174,9 +174,54 @@ int ProcessStatement::rewrite_as_always_edge_(Entity*, Architecture*) return -1; const Expression*ce_raw = stmt->peek_condition(); + // Now we have matched this pattern: + // process() begin if ... + // The is the condition. - // We expect the condition to be 'event AND ='1'. - // If it's not a logical AND, I give up. + if (const ExpFunc*ce_func = dynamic_cast(ce_raw)) { + if (ce_func->func_args() != 1) + return -1; + if (ce_func->func_name()!="rising_edge" && ce_func->func_name()!="falling_edge") + return -1; + + if (! se->symbolic_compare(ce_func->func_arg(0))) + return -1; + + // We've matched this pattern: + // process() if (rising_edge()) then ... + // and we can convert it to: + // always @(posedge ) ... + + ExpEdge::fun_t use_edge; + if (ce_func->func_name()=="rising_edge") + use_edge = ExpEdge::POSEDGE; + else if (ce_func->func_name()=="falling_edge") + use_edge = ExpEdge::NEGEDGE; + else + use_edge = ExpEdge::ANYEDGE; + + // Replace the sensitivity expression with an edge + // expression. The ExpEdge expression signals that this + // is an always-@(edge) statement. + ExpEdge*edge = new ExpEdge(use_edge, se); + assert(sensitivity_list_.size() == 1); + sensitivity_list_.pop_front(); + sensitivity_list_.push_front(edge); + + // 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(); + stmt->extract_true(statements_list_); + + delete stmt; + return 0; + } + + // Here we expect the condition to be + // 'event AND ='1'. + // So if ce_raw is not a logical AND, I give up. const ExpLogical*ce = dynamic_cast (ce_raw); if (ce == 0) return -1; diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index 6d24335f0..d779e484a 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -461,6 +461,10 @@ class ExpFunc : public Expression { ExpFunc(perm_string nn, std::list*args); ~ExpFunc(); + inline perm_string func_name() const { return name_; } + inline size_t func_args() const { return argv_.size(); } + inline const Expression*func_arg(size_t idx) const { return argv_[idx]; } + public: // Base methods int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); void write_to_stream(std::ostream&fd); diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index d4fa884e1..63c1f6eb5 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -554,6 +554,16 @@ int ExpFunc::emit(ostream&out, Entity*ent, Architecture*arc) errors += argv_[0]->emit(out, ent, arc); out << ")"; + } else if (name_ == "rising_edge" && argv_.size()==1) { + out << "$ivlh_rising_edge("; + errors += argv_[0]->emit(out, ent, arc); + out << ")"; + + } else if (name_ == "falling_edge" && argv_.size()==1) { + out << "$ivlh_falling_edge("; + errors += argv_[0]->emit(out, ent, arc); + out << ")"; + } else { out << "\\" << name_ << " ("; for (size_t idx = 0; idx < argv_.size() ; idx += 1) { From 3d5765949eb59cac19b118170e3a02d98eaf6ec3 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 5 Jun 2013 21:10:33 -0700 Subject: [PATCH 17/21] Some shorthand type marks in write_to_stream. --- vhdlpp/vtype_stream.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/vhdlpp/vtype_stream.cc b/vhdlpp/vtype_stream.cc index 661626e6a..ed21e5a99 100644 --- a/vhdlpp/vtype_stream.cc +++ b/vhdlpp/vtype_stream.cc @@ -17,9 +17,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +# define __STDC_LIMIT_MACROS # include "vtype.h" # include "expression.h" # include +# include # include using namespace std; @@ -115,6 +117,15 @@ void VTypePrimitive::write_to_stream(ostream&fd) const void VTypeRange::write_to_stream(ostream&fd) const { + // Detect some special cases that can be written as ieee or + // standard types. + if (const VTypePrimitive*tmp = dynamic_cast (base_)) { + if (min_==0 && max_==INT64_MAX && tmp->type()==VTypePrimitive::INTEGER) { + fd << "natural"; + return; + } + } + base_->write_to_stream(fd); fd << " range " << min_ << " to " << max_; } From d630e4dfe91f3756ec7bc40dd27142d48b106d3f Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 7 Jun 2013 15:47:14 -0700 Subject: [PATCH 18/21] Elaborate VHDL entity port types/expressions. We need to elaborate expressions so that function calls in expressions (i.e. ranges) get bound to their proper scope. This binding is in turn used to emit package scopes. This is particularly interesting for ports of entities. --- vhdlpp/Makefile.in | 7 ++++-- vhdlpp/entity_elaborate.cc | 7 +++++- vhdlpp/expression.cc | 5 ++-- vhdlpp/expression.h | 5 +++- vhdlpp/expression_elaborate.cc | 10 ++++++-- vhdlpp/expression_emit.cc | 12 +++++++++ vhdlpp/scope.cc | 14 +++++++++-- vhdlpp/subprogram.cc | 8 +++++- vhdlpp/subprogram.h | 5 ++++ vhdlpp/vtype.h | 10 +++++++- vhdlpp/vtype_elaborate.cc | 45 ++++++++++++++++++++++++++++++++++ 11 files changed, 116 insertions(+), 12 deletions(-) create mode 100644 vhdlpp/vtype_elaborate.cc diff --git a/vhdlpp/Makefile.in b/vhdlpp/Makefile.in index de6e0b8df..da356cc13 100644 --- a/vhdlpp/Makefile.in +++ b/vhdlpp/Makefile.in @@ -59,14 +59,17 @@ LIBS = @LIBS@ @EXTRALIBS@ M = StringHeap.o LineInfo.o O = main.o architec.o compiler.o entity.o \ - expression.o package.o scope.o sequential.o vsignal.o vtype.o \ + expression.o package.o scope.o sequential.o subprogram.o vsignal.o vtype.o \ + vtype_match.o \ architec_elaborate.o entity_elaborate.o expression_elaborate.o \ expression_evaluate.o \ sequential_elaborate.o \ + vtype_elaborate.o \ entity_stream.o expression_stream.o vtype_stream.o \ lexor.o lexor_keyword.o parse.o \ parse_misc.o library.o vhdlreal.o vhdlint.o \ - architec_emit.o entity_emit.o expression_emit.o sequential_emit.o vtype_emit.o \ + architec_emit.o entity_emit.o expression_emit.o package_emit.o \ + sequential_emit.o subprogram_emit.o vtype_emit.o \ debug.o architec_debug.o expression_debug.o sequential_debug.o \ $M diff --git a/vhdlpp/entity_elaborate.cc b/vhdlpp/entity_elaborate.cc index 2727bd34e..861029ca7 100644 --- a/vhdlpp/entity_elaborate.cc +++ b/vhdlpp/entity_elaborate.cc @@ -1,5 +1,6 @@ /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -113,6 +114,10 @@ int Entity::elaborate_ports_(void) continue; } + // Elaborate the type to elaborate any expressions that + // are used by the types. + errors += type->elaborate(this, bind_arch_); + VType::decl_t cur_decl; cur_decl.type = type; declarations_[cur_port->name] = cur_decl; diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index 5cb7be4d5..69c0485f7 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -1,5 +1,6 @@ /* * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -260,12 +261,12 @@ ExpEdge::~ExpEdge() } ExpFunc::ExpFunc(perm_string nn) -: name_(nn), argv_(0) +: name_(nn), def_(0) { } ExpFunc::ExpFunc(perm_string nn, list*args) -: name_(nn), argv_(args->size()) +: name_(nn), argv_(args->size()), def_(0) { for (size_t idx = 0; idx < argv_.size() ; idx += 1) { ivl_assert(*this, !args->empty()); diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index d779e484a..233afc0fe 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -1,7 +1,8 @@ #ifndef __expression_H #define __expression_H /* - * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -31,6 +32,7 @@ class prange_t; class Entity; class Architecture; class ScopeBase; +class Subprogram; class VType; class VTypeArray; class VTypePrimitive; @@ -474,6 +476,7 @@ class ExpFunc : public Expression { private: perm_string name_; std::vector argv_; + Subprogram*def_; }; class ExpInteger : public Expression { diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index a201de334..f88bdbb03 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -1,6 +1,6 @@ /* - * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) - * Copyright CERN 2012 / Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -637,6 +637,12 @@ int ExpFunc::elaborate_expr(Entity*ent, Architecture*arc, const VType*) { int errors = 0; + ivl_assert(*this, arc); + Subprogram*prog = arc->find_subprogram(name_); + + ivl_assert(*this, def_==0); + def_ = prog; + for (size_t idx = 0 ; idx < argv_.size() ; idx += 1) { const VType*tmp = argv_[idx]->probe_type(ent, arc); errors += argv_[idx]->elaborate_expr(ent, arc, tmp); diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 63c1f6eb5..07916d159 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -21,6 +21,7 @@ # include "expression.h" # include "vtype.h" # include "architec.h" +# include "package.h" # include "parse_types.h" # include # include @@ -565,6 +566,17 @@ int ExpFunc::emit(ostream&out, Entity*ent, Architecture*arc) out << ")"; } else { + // If this function has an elaborated defintion, and if + // that definition is in a package, then include the + // package name as a scope qualifier. This assures that + // the SV elaborator finds the correct VHDL elaborated + // definition. + if (def_) { + const Package*pkg = dynamic_cast (def_->get_parent()); + if (pkg != 0) + out << "\\" << pkg->name() << " ::"; + } + out << "\\" << name_ << " ("; for (size_t idx = 0; idx < argv_.size() ; idx += 1) { if (idx > 0) out << ", "; diff --git a/vhdlpp/scope.cc b/vhdlpp/scope.cc index 77ba7c4f6..c6f783628 100644 --- a/vhdlpp/scope.cc +++ b/vhdlpp/scope.cc @@ -1,5 +1,6 @@ /* - * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -57,6 +58,15 @@ ScopeBase::ScopeBase(const ActiveScope&ref) use_subprograms_ = ref.use_subprograms_; cur_subprograms_ = ref.cur_subprograms_; + + // 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, + // so set it now. + for (map::iterator cur = cur_subprograms_.begin() + ; cur != cur_subprograms_.end() ; ++ cur) { + cur->second->set_parent(this); + } } ScopeBase::~ScopeBase() @@ -148,7 +158,7 @@ Subprogram* ScopeBase::find_subprogram(perm_string name) const return cur->second; cur = use_subprograms_.find(name); - if (cur != use_subprograms_.find(name)) + if (cur != use_subprograms_.end()) return cur->second; return 0; diff --git a/vhdlpp/subprogram.cc b/vhdlpp/subprogram.cc index 25b6deb9d..47641550c 100644 --- a/vhdlpp/subprogram.cc +++ b/vhdlpp/subprogram.cc @@ -27,7 +27,7 @@ using namespace std; Subprogram::Subprogram(perm_string nam, list*ports, const VType*return_type) -: name_(nam), ports_(ports), return_type_(return_type), statements_(0) +: name_(nam), parent_(0), ports_(ports), return_type_(return_type), statements_(0) { } @@ -35,6 +35,12 @@ Subprogram::~Subprogram() { } +void Subprogram::set_parent(const ScopeBase*par) +{ + ivl_assert(*this, parent_ == 0); + parent_ = par; +} + void Subprogram::set_program_body(list*stmt) { ivl_assert(*this, statements_==0); diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h index ea12e3934..304fa06cf 100644 --- a/vhdlpp/subprogram.h +++ b/vhdlpp/subprogram.h @@ -26,6 +26,7 @@ # include class InterfacePort; +class ScopeBase; class SequentialStmt; class VType; @@ -36,6 +37,9 @@ class Subprogram : public LineInfo { const VType*return_type); ~Subprogram(); + void set_parent(const ScopeBase*par); + inline const ScopeBase*get_parent() const { return parent_; } + inline const perm_string&name() const { return name_; } void set_program_body(std::list*statements); @@ -52,6 +56,7 @@ class Subprogram : public LineInfo { private: perm_string name_; + const ScopeBase*parent_; std::list*ports_; const VType*return_type_; std::list*statements_; diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index 9d185ad0e..0c33b2566 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -1,7 +1,8 @@ #ifndef __vtype_H #define __vtype_H /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -27,6 +28,8 @@ # include # include "StringHeap.h" +class Architecture; +class Entity; class Expression; class prange_t; class VTypeDef; @@ -45,6 +48,10 @@ class VType { VType() { } virtual ~VType() =0; + // This is rarely used, but some types may have expressions + // that need to be elaborated. + virtual int elaborate(Entity*end, Architecture*arc) const; + // This virtual method returns true if that is equivalent to // this type. This method is used for example to compare // function prototypes. @@ -170,6 +177,7 @@ class VTypeArray : public VType { VTypeArray(const VType*etype, std::list*r, bool signed_vector =false); ~VTypeArray(); + int elaborate(Entity*ent, Architecture*arc) const; void write_to_stream(std::ostream&fd) const; void show(std::ostream&) const; diff --git a/vhdlpp/vtype_elaborate.cc b/vhdlpp/vtype_elaborate.cc new file mode 100644 index 000000000..f3611d9f4 --- /dev/null +++ b/vhdlpp/vtype_elaborate.cc @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * 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. + */ + +# include "vtype.h" +# include "expression.h" + +int VType::elaborate(Entity*, Architecture*) const +{ + return 0; +} + +int VTypeArray::elaborate(Entity*ent, Architecture*arc) const +{ + int errors = 0; + etype_->elaborate(ent, arc); + + for (vector::const_iterator cur = ranges_.begin() + ; cur != ranges_.end() ; ++ cur) { + + Expression*tmp = cur->msb(); + if (tmp) errors += tmp->elaborate_expr(ent, arc, 0); + + tmp = cur->lsb(); + if (tmp) errors += tmp->elaborate_expr(ent, arc, 0); + } + + return errors; +} From 8487cb561692aebe044061649612705ef2360d6c Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 7 Jun 2013 15:49:19 -0700 Subject: [PATCH 19/21] Do a better job of figuring the vtype of an expression. --- vhdlpp/expression.cc | 2 +- vhdlpp/expression.h | 6 ++++++ vhdlpp/expression_elaborate.cc | 23 +++++++++++++++++++++++ vhdlpp/vtype.h | 4 ++++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index 69c0485f7..74e143c63 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -40,7 +40,7 @@ Expression::~Expression() void Expression::set_type(const VType*typ) { - assert(type_ == 0); + assert(type_==0 || type_==typ); type_ = typ; } diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index 233afc0fe..e5c143e3e 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -193,6 +193,9 @@ class ExpBinary : public Expression { void dump_operands(ostream&out, int indent = 0) const; + private: + virtual const VType*resolve_operand_types_(const VType*t1, const VType*t2) const; + private: Expression*operand1_; Expression*operand2_; @@ -305,6 +308,9 @@ class ExpArithmetic : public ExpBinary { virtual bool evaluate(ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; + private: + const VType* resolve_operand_types_(const VType*t1, const VType*t2) const; + private: fun_t fun_; }; diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index f88bdbb03..2ca201d35 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -328,6 +328,9 @@ const VType* ExpBinary::probe_type(Entity*ent, Architecture*arc) const if (t1 == t2) return t1; + if (const VType*tb = resolve_operand_types_(t1, t2)) + return tb; + // FIXME: I should at this point try harder to find an // operator that has the proper argument list and use this // here, but for now we leave it for the back-end to figure out. @@ -337,6 +340,11 @@ const VType* ExpBinary::probe_type(Entity*ent, Architecture*arc) const return 0; } +const VType*ExpBinary::resolve_operand_types_(const VType*t1, const VType*t2) const +{ + return 0; +} + int ExpBinary::elaborate_exprs(Entity*ent, Architecture*arc, const VType*ltype) { int errors = 0; @@ -491,6 +499,21 @@ int ExpArithmetic::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltyp return errors; } +const VType* ExpArithmetic::resolve_operand_types_(const VType*t1, const VType*t2) const +{ + while (const VTypeRange*tmp = dynamic_cast (t1)) + t1 = tmp->base_type(); + while (const VTypeRange*tmp = dynamic_cast (t2)) + t2 = tmp->base_type(); + + if (t1->type_match(t2)) + return t1; + if (t2->type_match(t2)) + return t2; + + return 0; +} + const VType* ExpAttribute::probe_type(Entity*ent, Architecture*arc) const { base_->probe_type(ent, arc); diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index 0c33b2566..e18e9ecbd 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -205,6 +205,10 @@ class VTypeRange : public VType { VTypeRange(const VType*base, int64_t max_val, int64_t min_val); ~VTypeRange(); + // Get the type that is limited by the range. + inline const VType* base_type() const { return base_; } + + public: // Virtual methods void write_to_stream(std::ostream&fd) const; int emit_def(std::ostream&out) const; From 24bd630cb28cc99f2e1fae4f6e37fba322083bfc Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 10 Jun 2013 16:39:53 -0700 Subject: [PATCH 20/21] Parse (to sorry messages) unbounded array definitions. --- vhdlpp/package.cc | 6 ++++++ vhdlpp/parse.y | 33 ++++++++++++++++++++++++--------- vhdlpp/parse_misc.cc | 29 +++++++++++++++++++++++------ vhdlpp/parse_misc.h | 8 ++++---- vhdlpp/parse_types.h | 9 ++++++--- 5 files changed, 63 insertions(+), 22 deletions(-) diff --git a/vhdlpp/package.cc b/vhdlpp/package.cc index 44f9ca3bc..d3d4a8b06 100644 --- a/vhdlpp/package.cc +++ b/vhdlpp/package.cc @@ -68,6 +68,12 @@ void Package::write_to_stream(ostream&fd) const for (map::const_iterator cur = cur_constants_.begin() ; cur != cur_constants_.end() ; ++ cur) { + if (cur->second==0 || cur->second->typ==0) { + fd << "-- const " << cur->first + << " has errors." << endl; + continue; + } + fd << "constant " << cur->first << ": "; cur->second->typ->write_to_stream(fd); fd << " := "; diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 09c8e5f78..d21de7f84 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -6,8 +6,8 @@ %parse-param {perm_string parse_library_name} %{ /* - * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) - * Copyright CERN 2012 / Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -674,6 +674,15 @@ composite_type_definition delete $2; $$ = tmp; } + + /* unbounded_array_definition IEEE 1076-2008 P5.3.2.1 */ + | K_array '(' index_subtype_definition_list ')' K_of subtype_indication + { sorrymsg(@1, "unbounded_array_definition not supported.\n"); + std::list r; + VTypeArray*tmp = new VTypeArray($6, &r); + $$ = tmp; + } + | record_type_definition { $$ = $1; } ; @@ -1342,6 +1351,16 @@ index_constraint } ; + /* The identifier should be a type name */ +index_subtype_definition /* IEEE 1076-2008 P5.3.2.1 */ + : IDENTIFIER K_range BOX + ; + +index_subtype_definition_list + : index_subtype_definition_list ',' index_subtype_definition + | index_subtype_definition + ; + instantiation_list : identifier_list { @@ -2189,12 +2208,13 @@ subtype_indication delete[]$1; $$ = tmp; } - | IDENTIFIER '(' simple_expression direction simple_expression ')' - { const VType*tmp = calculate_subtype_array(@1, $1, active_scope, $3, $4, $5); + | IDENTIFIER index_constraint + { const VType*tmp = calculate_subtype_array(@1, $1, active_scope, $2); if (tmp == 0) { errormsg(@1, "Unable to calculate bounds for array of %s.\n", $1); } delete[]$1; + delete $2; $$ = tmp; } | IDENTIFIER K_range simple_expression direction simple_expression @@ -2205,11 +2225,6 @@ subtype_indication delete[]$1; $$ = tmp; } - | IDENTIFIER '(' error ')' - { errormsg(@1, "Syntax error in subtype indication.\n"); - yyerrok; - $$ = new VTypeERROR; - } ; suffix diff --git a/vhdlpp/parse_misc.cc b/vhdlpp/parse_misc.cc index 10c058966..0049388bf 100644 --- a/vhdlpp/parse_misc.cc +++ b/vhdlpp/parse_misc.cc @@ -1,5 +1,6 @@ /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011,2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -19,6 +20,7 @@ */ # include "parse_misc.h" +# include "parse_types.h" # include "parse_api.h" # include "entity.h" # include "architec.h" @@ -65,11 +67,11 @@ void bind_architecture_to_entity(const char*ename, Architecture*arch) } } -const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name, - ScopeBase* /* scope */, - Expression*array_left, - bool /* downto*/ , - Expression*array_right) +static const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name, + ScopeBase* /* scope */, + Expression*array_left, + bool /* downto*/ , + Expression*array_right) { const VType*base_type = parse_type_by_name(lex_strings.make(base_name)); @@ -98,6 +100,21 @@ const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name, return base_type; } +const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name, + ScopeBase*scope, list*ranges) +{ + if (ranges->size() == 1) { + prange_t*tmpr = ranges->front(); + Expression*lef = tmpr->expr_left(); + Expression*rig = tmpr->expr_right(); + return calculate_subtype_array(loc, base_name, scope, + lef, tmpr->is_downto(), rig); + } + + sorrymsg(loc, "Don't know how to handle multiple ranges here.\n"); + return 0; +} + const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name, ScopeBase*scope, Expression*range_left, diff --git a/vhdlpp/parse_misc.h b/vhdlpp/parse_misc.h index d54a648f9..1e4c27669 100644 --- a/vhdlpp/parse_misc.h +++ b/vhdlpp/parse_misc.h @@ -1,7 +1,8 @@ #ifndef __parse_misc_H #define __parse_misc_H /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011,2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -25,6 +26,7 @@ class ActiveScope; class Architecture; class Expression; class Package; +class prange_t; class ScopeBase; class VType; @@ -33,9 +35,7 @@ extern void bind_architecture_to_entity(const char*ename, Architecture*arch); extern const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name, ScopeBase*scope, - Expression*array_left, - bool downto, - Expression*array_right); + std::list*ranges); extern const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name, ScopeBase*scope, Expression*range_left, diff --git a/vhdlpp/parse_types.h b/vhdlpp/parse_types.h index 2a8b27520..fb9b5a9b5 100644 --- a/vhdlpp/parse_types.h +++ b/vhdlpp/parse_types.h @@ -1,7 +1,8 @@ #ifndef __parse_types_H #define __parse_types_H /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011,2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -74,10 +75,12 @@ class prange_t { ~prange_t() { delete left_; delete right_; } void dump(ostream&out, int indent) const; - Expression*msb() { return direction_? left_ : right_; } - Expression*lsb() { return direction_? right_: left_; } + inline Expression*msb() { return direction_? left_ : right_; } + inline Expression*lsb() { return direction_? right_: left_; } inline bool is_downto() const { return direction_; } + inline Expression*expr_left() { return left_; } + inline Expression*expr_right() { return right_; } private: Expression *left_, *right_; From ca9616dc7b3f7b29f237ae74bab751e085b8cd54 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 12 Jun 2013 14:01:43 -0700 Subject: [PATCH 21/21] Better simple_expression parse rules. --- vhdlpp/parse.y | 72 +++++++++++++++++++++++++++++++++++--------- vhdlpp/parse_types.h | 6 ++++ 2 files changed, 64 insertions(+), 14 deletions(-) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index d21de7f84..05c1dea36 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -233,6 +233,7 @@ static void touchup_interface_for_functions(std::list*ports) std::list*range_list; ExpArithmetic::fun_t arithmetic_op; + std::list*adding_terms; ExpAggregate::choice_t*choice; std::list*choice_list; @@ -287,6 +288,7 @@ static void touchup_interface_for_functions(std::list*ports) %type direction %type adding_operator +%type simple_expression_terms %type interface_element interface_list %type port_clause port_clause_opt @@ -314,7 +316,7 @@ static void touchup_interface_for_functions(std::list*ports) %type expression_logical_xnor expression_logical_xor %type name prefix selected_name %type shift_expression signal_declaration_assign_opt -%type simple_expression term waveform_element +%type simple_expression simple_expression_2 term waveform_element %type interface_element_expression %type waveform waveform_elements @@ -1788,12 +1790,12 @@ procedure_call $$ = tmp; } | IDENTIFIER '(' error ')' - { - errormsg(@1, "Errors in procedure call.\n"); - yyerrok; - delete[]$1; - $$ = 0; - }; + { errormsg(@1, "Errors in procedure call.\n"); + yyerrok; + delete[]$1; + $$ = 0; + } + ; procedure_call_statement : IDENTIFIER ':' procedure_call { $$ = $3; } @@ -2067,6 +2069,11 @@ sequential_statement shift_expression : simple_expression { $$ = $1; } ; +sign + : '+' + | '-' + ; + signal_declaration_assign_opt : VASSIGN expression { $$ = $2; } | { $$ = 0; } @@ -2085,18 +2092,55 @@ signal_declaration_assign_opt * Note that although the concatenation operator '&' is syntactically * an addition operator, it is handled differently during elaboration * so detect it and create a different expression type. + * + * Note too that I'm using *right* recursion to implement the {...} + * part of the rule. This is normally bad, but expression lists aren't + * normally that long, and the while loop going through the formed + * list fixes up the associations. */ simple_expression + : sign simple_expression_2 + { sorrymsg(@1, "Unary expression +- not supported.\n"); + $$ = $2; + } + | simple_expression_2 + { $$ = $1; } + ; + +simple_expression_2 : term { $$ = $1; } - | simple_expression adding_operator term - { Expression*tmp; - if ($2 == ExpArithmetic::xCONCAT) { - tmp = new ExpConcat($1, $3); - } else { - tmp = new ExpArithmetic($2, $1, $3); + | term simple_expression_terms + { Expression*tmp = $1; + list*lst = $2; + while (! lst->empty()) { + struct adding_term item = lst->front(); + lst->pop_front(); + if (item.op == ExpArithmetic::xCONCAT) + tmp = new ExpConcat(tmp, item.term); + else + tmp = new ExpArithmetic(item.op, tmp, item.term); } - FILE_NAME(tmp, @2); + delete lst; + $$ = tmp; + } + ; + +simple_expression_terms + : adding_operator term + { struct adding_term item; + item.op = $1; + item.term = $2; + list*tmp = new list; + tmp->push_back(item); + $$ = tmp; + } + | simple_expression_terms adding_operator term + { list*tmp = $1; + struct adding_term item; + item.op = $2; + item.term = $3; + tmp->push_back(item); $$ = tmp; } ; diff --git a/vhdlpp/parse_types.h b/vhdlpp/parse_types.h index fb9b5a9b5..2773aead8 100644 --- a/vhdlpp/parse_types.h +++ b/vhdlpp/parse_types.h @@ -90,4 +90,10 @@ class prange_t { prange_t(const prange_t&); prange_t operator=(const prange_t&); }; + +struct adding_term { + ExpArithmetic::fun_t op; + Expression*term; +}; + #endif