From d9fea802da0a534b669f00cbbd5bf505a1ba431a Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 5 May 2013 19:05:46 -0700 Subject: [PATCH 01/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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 From d346fb098fbea40f46287da2010b9b2960aeafb3 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 15 Jun 2013 16:24:02 -0400 Subject: [PATCH 22/30] Collect initializer statements in the pform. --- elab_scope.cc | 6 ++++++ pform_dump.cc | 11 +++++++++++ pform_pclass.cc | 12 ++++++++---- pform_types.h | 10 ++++++++++ 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index 91c1b9fb5..285122d3f 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -304,6 +304,12 @@ static void elaborate_scope_class(Design*des, NetScope*scope, << "Elaborate scope class " << pclass->pscope_name() << endl; } + if (! use_type->initialize.empty()) { + cerr << pclass->get_fileline() << ": sorry: " + << "Class property initializers not supported." << endl; + des->errors += 1; + } + // Class scopes have no parent scope, because references are // not allowed to escape a class method. NetScope*class_scope = new NetScope(0, hname_t(pclass->pscope_name()), diff --git a/pform_dump.cc b/pform_dump.cc index feb274697..2a1bd1e09 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -181,9 +181,19 @@ void class_type_t::pform_dump(ostream&out, unsigned indent) const ; cur != properties.end() ; ++cur) { out << " " << cur->first; } + out << " }" << endl; } +void class_type_t::pform_dump_init(ostream&out, unsigned indent) const +{ + for (vector::const_iterator cur = initialize.begin() + ; cur != initialize.end() ; ++cur) { + Statement*curp = *cur; + curp->dump(out,indent+4); + } +} + void struct_member_t::pform_dump(ostream&out, unsigned indent) const { out << setw(indent) << "" << type; @@ -1315,6 +1325,7 @@ void PClass::dump(ostream&out, unsigned indent) const { out << setw(indent) << "" << "class " << type->name << ";" << endl; type->pform_dump(out, indent+2); + type->pform_dump_init(out, indent+2); dump_tasks_(out, indent+2); dump_funcs_(out, indent+2); out << setw(indent) << "" << "endclass" << endl; diff --git a/pform_pclass.cc b/pform_pclass.cc index f21479659..61698f7c1 100644 --- a/pform_pclass.cc +++ b/pform_pclass.cc @@ -64,11 +64,15 @@ void pform_class_property(const struct vlltype&loc, use_type = new uarray_type_t(use_type, pd); } - if (curp->expr.get()) { - VLerror(loc, "sorry: Initialization expressions for properties not implemented."); - } - pform_cur_class->type->properties[curp->name] = use_type; + + if (PExpr*rval = curp->expr.release()) { + PExpr*lval = new PEIdent(curp->name); + FILE_NAME(lval, loc); + PAssign*tmp = new PAssign(lval, rval); + FILE_NAME(tmp, loc); + pform_cur_class->type->initialize.push_back(tmp); + } } } diff --git a/pform_types.h b/pform_types.h index e99b966fc..b834884c3 100644 --- a/pform_types.h +++ b/pform_types.h @@ -27,6 +27,7 @@ # include "ivl_target.h" # include # include +# include # include # include @@ -37,6 +38,7 @@ class Design; class NetScope; class PExpr; +class Statement; class ivl_type_s; typedef named named_number_t; typedef named named_pexpr_t; @@ -212,10 +214,18 @@ struct class_type_t : public data_type_t { : name(n) { } void pform_dump(std::ostream&out, unsigned indent) const; + void pform_dump_init(std::ostream&out, unsigned indent) const; + // This is the name of the class type. perm_string name; + // This is a map of the properties. Map the name to the type. std::map properties; + // This is an ordered list of property initializers. The name + // is the name of the property to be assigned, and the val is + // the expression that is assigned. + std::vector initialize; + ivl_type_s* elaborate_type(Design*, NetScope*) const; }; From 75b4b94061be1c11772c65c3e76b6a4487c8827f Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 16 Jun 2013 18:14:50 -0400 Subject: [PATCH 23/30] Elaborate implicit initializers Remaining pform fixup of property initializers, and elaboration and code generation for implicit constructor. --- elab_expr.cc | 24 +++++++++++++++++++++++- elab_scope.cc | 6 ------ elab_sig.cc | 2 +- parse.y | 2 +- pform.h | 2 +- pform_pclass.cc | 22 +++++++++++++++++++++- 6 files changed, 47 insertions(+), 11 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index dc24c0294..7d5fbca09 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -4464,13 +4464,35 @@ unsigned PENewClass::test_width(Design*, NetScope*, width_mode_t&) NetExpr* PENewClass::elaborate_expr(Design*des, NetScope*scope, ivl_type_t ntype, unsigned) const { - NetENew*obj = new NetENew(ntype); + NetExpr*obj = new NetENew(ntype); obj->set_line(*this); // Find the constructor for the class. If there is no // constructor then the result of this expression is the // allocation alone. const netclass_t*ctype = dynamic_cast (ntype); + + // If there is an initializer function, then pass the object + // through that function first. Note tha the initializer + // function has no arguments other then the object itself. + if (NetScope*new1_scope = ctype->method_from_name(perm_string::literal("new@"))) { + NetFuncDef*def1 = new1_scope->func_def(); + ivl_assert(*this, def1); + ivl_assert(*this, def1->port_count()==1); + vector parms1 (1); + parms1[0] = obj; + + // The return value of the initializer is the "this" + // variable, instead of the "new&" scope name. + NetNet*res1 = new1_scope->find_signal(perm_string::literal("@")); + ivl_assert(*this, res1); + + NetESignal*eres = new NetESignal(res1); + NetEUFunc*tmp = new NetEUFunc(scope, new1_scope, eres, parms1, true); + tmp->set_line(*this); + obj = tmp; + } + NetScope*new_scope = ctype->method_from_name(perm_string::literal("new")); if (new_scope == 0) { // No constructor. diff --git a/elab_scope.cc b/elab_scope.cc index 285122d3f..91c1b9fb5 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -304,12 +304,6 @@ static void elaborate_scope_class(Design*des, NetScope*scope, << "Elaborate scope class " << pclass->pscope_name() << endl; } - if (! use_type->initialize.empty()) { - cerr << pclass->get_fileline() << ": sorry: " - << "Class property initializers not supported." << endl; - des->errors += 1; - } - // Class scopes have no parent scope, because references are // not allowed to escape a class method. NetScope*class_scope = new NetScope(0, hname_t(pclass->pscope_name()), diff --git a/elab_sig.cc b/elab_sig.cc index 35e867426..b9701ebdf 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -538,7 +538,7 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const elaborate_sig_wires_(des, scope); NetNet*ret_sig; - if (gn_system_verilog() && fname == "new") { + if (gn_system_verilog() && fname=="new" || fname=="new@") { // Special case: this is a constructor, so the return // signal is also the first argument. For example, the // source code for the definition may be: diff --git a/parse.y b/parse.y index 70eb07bd3..f436f28b5 100644 --- a/parse.y +++ b/parse.y @@ -673,7 +673,7 @@ class_declaration /* IEEE1800-2005: A.1.2 */ } class_items_opt K_endclass { // Process a class. - pform_end_class_declaration(); + pform_end_class_declaration(@8); } class_declaration_endlabel_opt { // Wrap up the class. diff --git a/pform.h b/pform.h index e8c656fb8..a6f24e439 100644 --- a/pform.h +++ b/pform.h @@ -189,7 +189,7 @@ extern void pform_class_property(const struct vlltype&loc, extern void pform_set_this_class(const struct vlltype&loc, PTaskFunc*net); extern void pform_set_constructor_return(PFunction*net); -extern void pform_end_class_declaration(void); +extern void pform_end_class_declaration(const struct vlltype&loc); extern void pform_make_udp(perm_string name, list*parms, std::vector*decl, list*table, diff --git a/pform_pclass.cc b/pform_pclass.cc index 61698f7c1..c0ac9de55 100644 --- a/pform_pclass.cc +++ b/pform_pclass.cc @@ -111,9 +111,29 @@ PFunction*pform_push_constructor_scope(const struct vlltype&loc) return func; } -void pform_end_class_declaration(void) +void pform_end_class_declaration(const struct vlltype&loc) { assert(pform_cur_class); + + // If there were initializer statements, then collect them + // into an implicit constructor function. + if (! pform_cur_class->type->initialize.empty()) { + PFunction*func = pform_push_function_scope(loc, "new@", true); + func->set_ports(0); + pform_set_constructor_return(func); + pform_set_this_class(loc, func); + + class_type_t*use_class = pform_cur_class->type; + if (use_class->initialize.size() == 1) { + func->set_statement(use_class->initialize.front()); + } else { + PBlock*tmp = new PBlock(PBlock::BL_SEQ); + tmp->set_statement(use_class->initialize); + func->set_statement(tmp); + } + pform_pop_scope(); + } + pform_cur_class = 0; pform_pop_scope(); } From fbc5557a10dff9d4fc851ee25962c2898640dbaa Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 20 Jun 2013 17:26:16 -0400 Subject: [PATCH 24/30] Handle properties that have arbitrary bit widths. This fixes the run time handling of arbitrary width bit vectors as class properties. The vvp code generator already did the right things. --- parse.y | 2 +- vvp/class_type.cc | 50 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/parse.y b/parse.y index f436f28b5..f0bcbaa1b 100644 --- a/parse.y +++ b/parse.y @@ -769,7 +769,7 @@ class_item /* IEEE1800-2005: A.1.8 */ { current_function->set_ports($6); pform_set_constructor_return(current_function); pform_set_this_class(@3, current_function); - current_function_set_statement($10? @10 : @3, $10); + current_function_set_statement(@3, $10); pform_pop_scope(); current_function = 0; } diff --git a/vvp/class_type.cc b/vvp/class_type.cc index 5b6791eb0..8f61c50da 100644 --- a/vvp/class_type.cc +++ b/vvp/class_type.cc @@ -141,6 +141,31 @@ template class property_atom : public class_property_t { void copy(char*dst, char*src); }; +class property_bit : public class_property_t { + public: + inline property_bit(size_t wid): wid_(wid) { } + ~property_bit() { } + + size_t instance_size() const { return sizeof(vvp_vector2_t); } + + public: + void construct(char*buf) const + { new (buf+offset_) vvp_vector2_t (0, wid_); } + + void destruct(char*buf) const + { vvp_vector2_t*tmp = reinterpret_cast(buf+offset_); + tmp->~vvp_vector2_t(); + } + + void set_vec4(char*buf, const vvp_vector4_t&val); + void get_vec4(char*buf, vvp_vector4_t&val); + + void copy(char*dst, char*src); + + private: + size_t wid_; +}; + template class property_real : public class_property_t { public: inline explicit property_real(void) { } @@ -234,6 +259,25 @@ template void property_atom::copy(char*dst, char*src) *dst_obj = *src_obj; } +void property_bit::set_vec4(char*buf, const vvp_vector4_t&val) +{ + vvp_vector2_t*obj = reinterpret_cast (buf+offset_); + *obj = val; +} + +void property_bit::get_vec4(char*buf, vvp_vector4_t&val) +{ + vvp_vector2_t*obj = reinterpret_cast (buf+offset_); + val = vector2_to_vector4(*obj, obj->size()); +} + +void property_bit::copy(char*dst, char*src) +{ + vvp_vector2_t*dst_obj = reinterpret_cast (dst+offset_); + vvp_vector2_t*src_obj = reinterpret_cast (src+offset_); + *dst_obj = *src_obj; +} + template void property_real::set_real(char*buf, double val) { T*tmp = reinterpret_cast(buf+offset_); @@ -326,8 +370,12 @@ void class_type::set_property(size_t idx, const string&name, const string&type) properties_[idx].type = new property_string; else if (type == "o") properties_[idx].type = new property_object; - else + else if (type[0] == 'b') { + size_t wid = strtoul(type.c_str()+1, 0, 0); + properties_[idx].type = new property_bit(wid); + } else { properties_[idx].type = 0; + } } void class_type::finish_setup(void) From 637d43fb5a9557653ca239a8d8aa7fc4fa2da6b1 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 24 Jun 2013 08:29:28 -0400 Subject: [PATCH 25/30] Add support for logic vector properties in classes. This is similar to but not the same as bit(bool) vector properties in classes. --- tgt-vvp/stmt_assign.c | 18 ++++++++++++++++- vvp/class_type.cc | 47 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index e98ec1d1f..c4eadd1b6 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -872,7 +872,23 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net) struct vector_info val = draw_eval_expr_wid(rval, wid, STUFF_OK_XZ); fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); - fprintf(vvp_out, " %%store/prop/v %d, %u, %u;\n", prop_idx, val.base, val.wid); + fprintf(vvp_out, " %%store/prop/v %d, %u, %u; Store in bool property %s\n", + prop_idx, val.base, val.wid, + ivl_type_prop_name(sig_type, prop_idx)); + fprintf(vvp_out, " %%pop/obj 1;\n"); + clr_vector(val); + + } else if (ivl_type_base(prop_type) == IVL_VT_LOGIC) { + assert(ivl_type_packed_dimensions(prop_type) == 1); + assert(ivl_type_packed_msb(prop_type,0) >= ivl_type_packed_lsb(prop_type, 0)); + int wid = ivl_type_packed_msb(prop_type,0) - ivl_type_packed_lsb(prop_type,0) + 1; + + struct vector_info val = draw_eval_expr_wid(rval, wid, STUFF_OK_XZ); + + fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); + fprintf(vvp_out, " %%store/prop/v %d, %u, %u; Store in logic property %s\n", + prop_idx, val.base, val.wid, + ivl_type_prop_name(sig_type, prop_idx)); fprintf(vvp_out, " %%pop/obj 1;\n"); clr_vector(val); diff --git a/vvp/class_type.cc b/vvp/class_type.cc index 8f61c50da..38768aa03 100644 --- a/vvp/class_type.cc +++ b/vvp/class_type.cc @@ -166,6 +166,31 @@ class property_bit : public class_property_t { size_t wid_; }; +class property_logic : public class_property_t { + public: + inline property_logic(size_t wid): wid_(wid) { } + ~property_logic() { } + + size_t instance_size() const { return sizeof(vvp_vector4_t); } + + public: + void construct(char*buf) const + { new (buf+offset_) vvp_vector4_t (0, wid_); } + + void destruct(char*buf) const + { vvp_vector4_t*tmp = reinterpret_cast(buf+offset_); + tmp->~vvp_vector4_t(); + } + + void set_vec4(char*buf, const vvp_vector4_t&val); + void get_vec4(char*buf, vvp_vector4_t&val); + + void copy(char*dst, char*src); + + private: + size_t wid_; +}; + template class property_real : public class_property_t { public: inline explicit property_real(void) { } @@ -278,6 +303,25 @@ void property_bit::copy(char*dst, char*src) *dst_obj = *src_obj; } +void property_logic::set_vec4(char*buf, const vvp_vector4_t&val) +{ + vvp_vector4_t*obj = reinterpret_cast (buf+offset_); + *obj = val; +} + +void property_logic::get_vec4(char*buf, vvp_vector4_t&val) +{ + vvp_vector4_t*obj = reinterpret_cast (buf+offset_); + val = *obj; +} + +void property_logic::copy(char*dst, char*src) +{ + vvp_vector4_t*dst_obj = reinterpret_cast (dst+offset_); + vvp_vector4_t*src_obj = reinterpret_cast (src+offset_); + *dst_obj = *src_obj; +} + template void property_real::set_real(char*buf, double val) { T*tmp = reinterpret_cast(buf+offset_); @@ -373,6 +417,9 @@ void class_type::set_property(size_t idx, const string&name, const string&type) else if (type[0] == 'b') { size_t wid = strtoul(type.c_str()+1, 0, 0); properties_[idx].type = new property_bit(wid); + } else if (type[0] == 'L') { + size_t wid = strtoul(type.c_str()+1,0,0); + properties_[idx].type = new property_logic(wid); } else { properties_[idx].type = 0; } From 046535cfbb2cfba072636458fad4b281e72268bc Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 24 Jun 2013 16:42:28 -0400 Subject: [PATCH 26/30] Blend implicit constructor with explicit constructor Class types that have both implicit construction and an explicit constructor can blend the implicit and explicit construction into the "new" function defined by the user. This doesn't change the behavior any, but removes a function call and related scope. --- PTask.h | 2 ++ Statement.cc | 12 +++++++++++ Statement.h | 4 ++++ elab_scope.cc | 60 ++++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 75 insertions(+), 3 deletions(-) diff --git a/PTask.h b/PTask.h index cbd2d7e2a..a79e5f95c 100644 --- a/PTask.h +++ b/PTask.h @@ -110,6 +110,8 @@ class PFunction : public PTaskFunc { void set_statement(Statement *s); void set_return(const data_type_t*t); + inline Statement* get_statement() { return statement_; } + void elaborate_scope(Design*des, NetScope*scope) const; /* elaborate the ports and return value. */ diff --git a/Statement.cc b/Statement.cc index 79d63fb63..5ce819311 100644 --- a/Statement.cc +++ b/Statement.cc @@ -21,6 +21,7 @@ # include "Statement.h" # include "PExpr.h" +# include "ivl_assert.h" Statement::~Statement() { @@ -126,6 +127,17 @@ void PBlock::set_statement(const vector&st) list_ = st; } +void PBlock::push_statement_front(Statement*that) +{ + ivl_assert(*this, bl_type_==BL_SEQ); + + list_.resize(list_.size()+1); + for (size_t idx = list_.size()-1 ; idx > 0 ; idx -= 1) + list_[idx] = list_[idx-1]; + + list_[0] = that; +} + PCallTask::PCallTask(const pform_name_t&n, const list&p) : package_(0), path_(n), parms_(p.size()) { diff --git a/Statement.h b/Statement.h index 43f299443..82289be76 100644 --- a/Statement.h +++ b/Statement.h @@ -186,6 +186,10 @@ class PBlock : public PScope, public Statement { void set_statement(const std::vector&st); + // Copy the statement from that block to the front of this + // block. + void push_statement_front(Statement*that); + virtual void dump(ostream&out, unsigned ind) const; virtual NetProc* elaborate(Design*des, NetScope*scope) const; virtual void elaborate_scope(Design*des, NetScope*scope) const; diff --git a/elab_scope.cc b/elab_scope.cc index 91c1b9fb5..7c9ddf3c3 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -293,8 +293,60 @@ static void elaborate_scope_enumerations(Design*des, NetScope*scope, } } -static void elaborate_scope_class(Design*des, NetScope*scope, - PClass*pclass) +/* + * If the pclass includes an implicit and explicit constructor, then + * merge the implicit constructor into the explicit constructor as + * statements in the beginning. + * + * This is not necessary for proper functionality, it is an + * optimization, so we can easily give up if it doesn't seem like it + * will obviously work. + */ +static void blend_class_constructors(PClass*pclass) +{ + perm_string new1 = perm_string::literal("new"); + perm_string new2 = perm_string::literal("new@"); + + map::iterator iter_new = pclass->funcs.find(new1); + if (iter_new == pclass->funcs.end()) + return; + + map::iterator iter_new2 = pclass->funcs.find(new2); + if (iter_new2 == pclass->funcs.end()) + return; + + PFunction*use_new = iter_new->second; + PFunction*use_new2 = iter_new2->second; + + // These constructors must be methods of the same class. + ivl_assert(*use_new, use_new->method_of() == use_new2->method_of()); + + Statement*def_new = use_new->get_statement(); + Statement*def_new2 = use_new2->get_statement(); + + // If either constructor has no definition, then give up. This + // might happen, for example, during parse errors or other + // degenerate situations. + if (def_new==0 || def_new2==0) + return; + + PBlock*blk_new = dynamic_cast (def_new); + + // For now, only do this if the functions are defined by + // statement blocks. That should be true by definition for + // implicit constructors, and common for explicit constructors. + if (blk_new==0) + return; + + ivl_assert(*blk_new, blk_new ->bl_type()==PBlock::BL_SEQ); + + blk_new->push_statement_front(def_new2); + + pclass->funcs.erase(iter_new2); + delete use_new2; +} + +static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) { class_type_t*use_type = pclass->type; netclass_t*use_class = new netclass_t(use_type->name); @@ -367,8 +419,10 @@ static void elaborate_scope_class(Design*des, NetScope*scope, static void elaborate_scope_classes(Design*des, NetScope*scope, const vector&classes) { - for (size_t idx = 0 ; idx < classes.size() ; idx += 1) + for (size_t idx = 0 ; idx < classes.size() ; idx += 1) { + blend_class_constructors(classes[idx]); elaborate_scope_class(des, scope, classes[idx]); + } } static void replace_scope_parameters_(NetScope*scope, const LineInfo&loc, From cf47a759d175454203ada18c27afa7856a5a4e27 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 26 Jun 2013 09:16:24 -0400 Subject: [PATCH 27/30] Implement the "local" class member protection. Test during elaboration that the member really is accessible in the context where the elaboration happens. --- elab_expr.cc | 47 ++++++++++++++++++++++++++++++++++------- elab_lval.cc | 18 ++++++++++++---- elab_scope.cc | 6 +++--- net_assign.cc | 15 +++++++------ netclass.cc | 32 +++++++++++++++++----------- netclass.h | 14 ++++++++++--- parse.y | 12 +++++------ pform_dump.cc | 2 +- pform_pclass.cc | 3 ++- pform_types.h | 41 +++++++----------------------------- property_qual.h | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 169 insertions(+), 77 deletions(-) create mode 100644 property_qual.h diff --git a/elab_expr.cc b/elab_expr.cc index 7d5fbca09..68f19b24c 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1135,7 +1135,11 @@ unsigned PECallFunction::test_width_method_(Design*des, NetScope*scope, } const netclass_t* class_type = net->class_type(); - member_type = class_type->get_property(member_name); + int midx = class_type->property_idx_from_name(member_name); + if (midx >= 0) + member_type = class_type->get_prop_type(midx); + else + member_type = 0; use_path = tmp_path; use_darray = dynamic_cast (member_type); @@ -1756,14 +1760,13 @@ static NetExpr* check_for_struct_members(const LineInfo*li, } static NetExpr* check_for_class_property(const LineInfo*li, - Design*des, NetScope*, + Design*des, NetScope*scope, NetNet*net, const name_component_t&comp) { const netclass_t*class_type = net->class_type(); - const ivl_type_s*ptype = class_type->get_property(comp.name); - - if (ptype == 0) { + int pidx = class_type->property_idx_from_name(comp.name); + if (pidx < 0) { cerr << li->get_fileline() << ": error: " << "Class " << class_type->get_name() << " has no property " << comp.name << "." << endl; @@ -1771,6 +1774,23 @@ static NetExpr* check_for_class_property(const LineInfo*li, return 0; } + if (debug_elaborate) { + cerr << li->get_fileline() << ": check_for_class_property: " + << "Property " << comp.name + << " of net " << net->name() + << ", context scope=" << scope_path(scope) + << endl; + } + + property_qualifier_t qual = class_type->get_prop_qual(pidx); + if (qual.test_local() && ! class_type->test_scope_is_method(scope)) { + cerr << li->get_fileline() << ": error: " + << "Local property " << class_type->get_prop_name(pidx) + << " is not accessible in this context." + << " (scope=" << scope_path(scope) << ")" << endl; + des->errors += 1; + } + NetEProperty*tmp = new NetEProperty(net, comp.name); tmp->set_line(*li); return tmp; @@ -2715,8 +2735,9 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) } if (const netclass_t*class_type = net->class_type()) { - const ivl_type_s*ptype = class_type->get_property(method_name); - if (ptype) { + int pidx = class_type->property_idx_from_name(method_name); + if (pidx >= 0) { + ivl_type_t ptype = class_type->get_prop_type(pidx); expr_type_ = ptype->base_type(); expr_width_ = ptype->packed_width(); min_width_ = expr_width_; @@ -2823,7 +2844,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, * not a method, or the name is not in the parent class, then * fail. Otherwise, return a NetEProperty. */ -NetExpr* PEIdent::elaborate_expr_class_member_(Design*, NetScope*scope, +NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope, unsigned, unsigned) const { if (!gn_system_verilog()) @@ -2854,9 +2875,19 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*, NetScope*scope, cerr << get_fileline() << ": PEIdent::elaborate_expr_class_member: " << "Found member " << member_name << " is a member of class " << class_type->get_name() + << ", context scope=" << scope_path(scope) << ", so synthesizing a NetEProperty." << endl; } + property_qualifier_t qual = class_type->get_prop_qual(pidx); + if (qual.test_local() && ! class_type->test_scope_is_method(scope)) { + cerr << get_fileline() << ": error: " + << "Local property " << class_type->get_prop_name(pidx) + << " is not accessible in this context." + << " (scope=" << scope_path(scope) << ")" << endl; + des->errors += 1; + } + NetEProperty*tmp = new NetEProperty(this_net, member_name); tmp->set_line(*this); return tmp; diff --git a/elab_lval.cc b/elab_lval.cc index 7e1d5193a..86cecdcb0 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -316,7 +316,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, return lv; } -NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*, +NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des, NetScope*scope) const { if (!gn_system_verilog()) @@ -812,7 +812,7 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, return true; } -bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*, +bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope, NetAssign_*lv, const perm_string&method_name) const { @@ -827,16 +827,26 @@ bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*, /* Make sure the property is really present in the class. If not, then generate an error message and return an error. */ - ivl_type_t ptype = class_type->get_property(method_name); - if (ptype == 0) { + int pidx = class_type->property_idx_from_name(method_name); + if (pidx < 0) { cerr << get_fileline() << ": error: Class " << class_type->get_name() << " does not have a property " << method_name << "." << endl; des->errors += 1; return false; } + property_qualifier_t qual = class_type->get_prop_qual(pidx); + if (qual.test_local() && ! class_type->test_scope_is_method(scope)) { + cerr << get_fileline() << ": error: " + << "Local property " << class_type->get_prop_name(pidx) + << " is not accessible (l-value) in this context." + << " (scope=" << scope_path(scope) << ")" << endl; + des->errors += 1; + } + lv->set_property(method_name); + ivl_type_t ptype = class_type->get_prop_type(pidx); const netdarray_t*mtype = dynamic_cast (ptype); if (mtype) { const name_component_t&name_tail = path_.back(); diff --git a/elab_scope.cc b/elab_scope.cc index 7c9ddf3c3..7b0aa224a 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -366,15 +366,15 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) // Collect the properties, elaborate them, and add them to the // elaborated class definition. - for (map::iterator cur = use_type->properties.begin() + for (map::iterator cur = use_type->properties.begin() ; cur != use_type->properties.end() ; ++ cur) { if (debug_scopes) { cerr << pclass->get_fileline() << ": elaborate_scope_class: " << " Property " << cur->first << endl; } - ivl_type_s*tmp = cur->second->elaborate_type(des, scope); + ivl_type_s*tmp = cur->second.type->elaborate_type(des, scope); ivl_assert(*pclass, tmp); - use_class->set_property(cur->first, tmp); + use_class->set_property(cur->first, cur->second.qual, tmp); } for (map::iterator cur = pclass->tasks.begin() diff --git a/net_assign.cc b/net_assign.cc index d787478a8..0562fb1e5 100644 --- a/net_assign.cc +++ b/net_assign.cc @@ -96,9 +96,9 @@ unsigned NetAssign_::lwidth() const if (member_.nil()) return 1; - const ivl_type_s*ptype = class_type->get_property(member_); - ivl_assert(*sig_, ptype); - + int pidx = class_type->property_idx_from_name(member_); + ivl_assert(*sig_, pidx >= 0); + ivl_type_t ptype = class_type->get_prop_type(pidx); return ptype->packed_width(); } @@ -118,7 +118,9 @@ ivl_variable_type_t NetAssign_::expr_type() const if (member_.nil()) return sig_->data_type(); - const ivl_type_s*tmp = class_type->get_property(member_); + int pidx = class_type->property_idx_from_name(member_); + ivl_assert(*sig_, pidx >= 0); + ivl_type_t tmp = class_type->get_prop_type(pidx); return tmp->base_type(); } @@ -138,8 +140,9 @@ const ivl_type_s* NetAssign_::net_type() const if (member_.nil()) return sig_->net_type(); - const ivl_type_s*tmp = class_type->get_property(member_); - ivl_assert(*sig_, tmp); + int pidx = class_type->property_idx_from_name(member_); + ivl_assert(*sig_, pidx >= 0); + ivl_type_t tmp = class_type->get_prop_type(pidx); return tmp; } diff --git a/netclass.cc b/netclass.cc index 690443f13..91636b95d 100644 --- a/netclass.cc +++ b/netclass.cc @@ -32,7 +32,7 @@ netclass_t::~netclass_t() { } -bool netclass_t::set_property(perm_string pname, ivl_type_s*ptype) +bool netclass_t::set_property(perm_string pname, property_qualifier_t qual, ivl_type_s*ptype) { map::const_iterator cur; cur = properties_.find(pname); @@ -41,6 +41,7 @@ bool netclass_t::set_property(perm_string pname, ivl_type_s*ptype) prop_t tmp; tmp.name = pname; + tmp.qual = qual; tmp.type = ptype; property_table_.push_back(tmp); @@ -59,17 +60,6 @@ ivl_variable_type_t netclass_t::base_type() const return IVL_VT_CLASS; } -const ivl_type_s* netclass_t::get_property(perm_string pname) const -{ - map::const_iterator cur; - cur = properties_.find(pname); - if (cur == properties_.end()) - return 0; - - assert(property_table_.size() > cur->second); - return property_table_[cur->second].type; -} - int netclass_t::property_idx_from_name(perm_string pname) const { map::const_iterator cur; @@ -86,6 +76,12 @@ const char*netclass_t::get_prop_name(size_t idx) const return property_table_[idx].name; } +property_qualifier_t netclass_t::get_prop_qual(size_t idx) const +{ + assert(idx < property_table_.size()); + return property_table_[idx].qual; +} + ivl_type_t netclass_t::get_prop_type(size_t idx) const { assert(idx < property_table_.size()); @@ -99,3 +95,15 @@ NetScope*netclass_t::method_from_name(perm_string name) const return task; } + +bool netclass_t::test_scope_is_method(const NetScope*scope) const +{ + while (scope && scope != class_scope_) { + scope = scope->parent(); + } + + if (scope == 0) + return false; + else + return true; +} diff --git a/netclass.h b/netclass.h index 30bd1d087..8aac64583 100644 --- a/netclass.h +++ b/netclass.h @@ -22,6 +22,7 @@ # include "LineInfo.h" # include "ivl_target.h" # include "nettypes.h" +# include "property_qual.h" # include # include @@ -37,7 +38,7 @@ class netclass_t : public ivl_type_s { // Set the property of the class during elaboration. Set the // name and type, and return true. If the name is already // present, then return false. - bool set_property(perm_string pname, ivl_type_s*ptype); + bool set_property(perm_string pname, property_qualifier_t qual, ivl_type_s*ptype); // Set the scope for the class. The scope has no parents and // is used for the elaboration of methods (tasks/functions). @@ -50,17 +51,23 @@ class netclass_t : public ivl_type_s { // This is the name of the class type inline perm_string get_name() const { return name_; } - const ivl_type_s* get_property(perm_string pname) const; - inline size_t get_properties(void) const { return properties_.size(); } + // Get information about each property. const char*get_prop_name(size_t idx) const; + property_qualifier_t get_prop_qual(size_t idx) const; ivl_type_t get_prop_type(size_t idx) const; + // Map the name of a property to its index. int property_idx_from_name(perm_string pname) const; // The task method scopes from the method name. NetScope*method_from_name(perm_string mname) const; + // Test if this scope is a method within the class. This is + // used to check scope for handling data protection keywords + // "local" and "protected". + bool test_scope_is_method(const NetScope*scope) const; + void elaborate_sig(Design*des, PClass*pclass); void elaborate(Design*des, PClass*pclass); @@ -75,6 +82,7 @@ class netclass_t : public ivl_type_s { // Vector of properties. struct prop_t { perm_string name; + property_qualifier_t qual; ivl_type_s* type; }; std::vector property_table_; diff --git a/parse.y b/parse.y index f0bcbaa1b..bc120c050 100644 --- a/parse.y +++ b/parse.y @@ -832,9 +832,9 @@ class_item /* IEEE1800-2005: A.1.8 */ ; class_item_qualifier /* IEEE1800-2005 A.1.8 */ - : K_static { $$ = property_qualifier_t::set_static(); } - | K_protected { $$ = property_qualifier_t::set_protected(); } - | K_local { $$ = property_qualifier_t::set_local(); } + : K_static { $$ = property_qualifier_t::make_static(); } + | K_protected { $$ = property_qualifier_t::make_protected(); } + | K_local { $$ = property_qualifier_t::make_local(); } ; class_new /* IEEE1800-2005 A.2.4 */ @@ -1493,7 +1493,7 @@ property_qualifier /* IEEE1800-2005 A.1.8 */ property_qualifier_opt /* IEEE1800-2005 A.1.8: ... { property_qualifier } */ : property_qualifier_list { $$ = $1; } - | { $$ = property_qualifier_t::set_none(); } + | { $$ = property_qualifier_t::make_none(); } ; property_qualifier_list /* IEEE1800-2005 A.1.8 */ @@ -1502,8 +1502,8 @@ property_qualifier_list /* IEEE1800-2005 A.1.8 */ ; random_qualifier /* IEEE1800-2005 A.1.8 */ - : K_rand { $$ = property_qualifier_t::set_rand(); } - | K_randc { $$ = property_qualifier_t::set_randc(); } + : K_rand { $$ = property_qualifier_t::make_rand(); } + | K_randc { $$ = property_qualifier_t::make_randc(); } ; /* real and realtime are exactly the same so save some code diff --git a/pform_dump.cc b/pform_dump.cc index 2a1bd1e09..41251c679 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -177,7 +177,7 @@ void class_type_t::pform_dump(ostream&out, unsigned indent) const { out << setw(indent) << "" << "class " << name << " {"; - for (map::const_iterator cur = properties.begin() + for (map::const_iterator cur = properties.begin() ; cur != properties.end() ; ++cur) { out << " " << cur->first; } diff --git a/pform_pclass.cc b/pform_pclass.cc index c0ac9de55..05907aceb 100644 --- a/pform_pclass.cc +++ b/pform_pclass.cc @@ -64,7 +64,8 @@ void pform_class_property(const struct vlltype&loc, use_type = new uarray_type_t(use_type, pd); } - pform_cur_class->type->properties[curp->name] = use_type; + pform_cur_class->type->properties[curp->name] + = class_type_t::prop_info_t(property_qual,use_type); if (PExpr*rval = curp->expr.release()) { PExpr*lval = new PEIdent(curp->name); diff --git a/pform_types.h b/pform_types.h index b834884c3..bf657a474 100644 --- a/pform_types.h +++ b/pform_types.h @@ -24,6 +24,7 @@ # include "LineInfo.h" # include "verinum.h" # include "named.h" +# include "property_qual.h" # include "ivl_target.h" # include # include @@ -219,7 +220,13 @@ struct class_type_t : public data_type_t { // This is the name of the class type. perm_string name; // This is a map of the properties. Map the name to the type. - std::map properties; + struct prop_info_t { + inline prop_info_t() : qual(property_qualifier_t::make_none()), type(0) { } + inline prop_info_t(property_qualifier_t q, data_type_t*t) : qual(q), type(t) { } + property_qualifier_t qual; + data_type_t* type; + }; + std::map properties; // This is an ordered list of property initializers. The name // is the name of the property to be assigned, and the val is @@ -229,38 +236,6 @@ struct class_type_t : public data_type_t { ivl_type_s* elaborate_type(Design*, NetScope*) const; }; -class property_qualifier_t { - public: - static inline property_qualifier_t set_none() - { property_qualifier_t res; res.mask_ = 0; return res; } - - static inline property_qualifier_t set_static() - { property_qualifier_t res; res.mask_ = 1; return res; } - - static inline property_qualifier_t set_protected() - { property_qualifier_t res; res.mask_ = 2; return res; } - - static inline property_qualifier_t set_local() - { property_qualifier_t res; res.mask_ = 4; return res; } - - static inline property_qualifier_t set_rand() - { property_qualifier_t res; res.mask_ = 8; return res; } - - static inline property_qualifier_t set_randc() - { property_qualifier_t res; res.mask_ = 16; return res; } - - inline property_qualifier_t operator | (property_qualifier_t r) - { property_qualifier_t res; res.mask_ = mask_ | r.mask_; return res; } - - public: - inline bool test_static() const { return mask_ & 1; } - inline bool test_protected() const { return mask_ & 2; } - inline bool test_local() const { return mask_ & 4; } - - private: - int mask_; -}; - /* * The pform_name_t is the general form for a hierarchical * identifier. It is an ordered list of name components. Each name diff --git a/property_qual.h b/property_qual.h new file mode 100644 index 000000000..df02c7080 --- /dev/null +++ b/property_qual.h @@ -0,0 +1,56 @@ +#ifndef __property_qual_H +#define __property_qual_H +/* + * Copyright (c) 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. + */ + +class property_qualifier_t { + public: + static inline property_qualifier_t make_none() + { property_qualifier_t res; res.mask_ = 0; return res; } + + static inline property_qualifier_t make_static() + { property_qualifier_t res; res.mask_ = 1; return res; } + + static inline property_qualifier_t make_protected() + { property_qualifier_t res; res.mask_ = 2; return res; } + + static inline property_qualifier_t make_local() + { property_qualifier_t res; res.mask_ = 4; return res; } + + static inline property_qualifier_t make_rand() + { property_qualifier_t res; res.mask_ = 8; return res; } + + static inline property_qualifier_t make_randc() + { property_qualifier_t res; res.mask_ = 16; return res; } + + inline property_qualifier_t operator | (property_qualifier_t r) + { property_qualifier_t res; res.mask_ = mask_ | r.mask_; return res; } + + public: + inline bool test_static() const { return mask_ & 1; } + inline bool test_protected() const { return mask_ & 2; } + inline bool test_local() const { return mask_ & 4; } + inline bool test_rand() const { return mask_ & 8; } + inline bool test_randc() const { return mask_ & 16; } + + private: + int mask_; +}; + +#endif From 4ef3ac5ca66428ebc1dc8072cab80f82f875fadc Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 28 Jun 2013 10:57:35 -0400 Subject: [PATCH 28/30] Implement const properties of classes. This implementation works by detecting assignments to constant properties in elaboration. Allow initializer assignments to assign to the constant, error all other assignments, and otherwise treat the constant like any other property. --- elab_lval.cc | 40 ++++++++++++++++++++++++++++++++++++++++ elaborate.cc | 7 +++++++ netclass.cc | 26 ++++++++++++++++++++++++++ netclass.h | 10 ++++++++++ parse.y | 19 ++++++++++++++++++- property_qual.h | 4 ++++ 6 files changed, 105 insertions(+), 1 deletion(-) diff --git a/elab_lval.cc b/elab_lval.cc index 86cecdcb0..3c5c8011e 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -343,6 +343,40 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des, return 0; } + // Detect assignment to constant properties. Note that the + // initializer constructor MAY assign to constant properties, + // as this is how the property gets its value. + property_qualifier_t qual = class_type->get_prop_qual(pidx); + if (qual.test_const()) { + if (class_type->get_prop_initialized(pidx)) { + cerr << get_fileline() << ": error: " + << "Property " << class_type->get_prop_name(pidx) + << " is constant in this method." + << " (scope=" << scope_path(scope) << ")" << endl; + des->errors += 1; + + } else if (scope->basename()!="new" && scope->basename()!="new@") { + cerr << get_fileline() << ": error: " + << "Property " << class_type->get_prop_name(pidx) + << " is constant in this method." + << " (scope=" << scope_path(scope) << ")" << endl; + des->errors += 1; + + } else { + + // Mark this property as initilized. This is used + // to know that we have initialized the constant + // object so the next assignment will be marked as + // illegal. + class_type->set_prop_initialized(pidx); + + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_lval_method_class_member_: " + << "Found initilzers for property " << class_type->get_prop_name(pidx) << endl; + } + } + } + NetAssign_*this_lval = new NetAssign_(this_net); this_lval->set_property(member_name); @@ -842,6 +876,12 @@ bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope, << " is not accessible (l-value) in this context." << " (scope=" << scope_path(scope) << ")" << endl; des->errors += 1; + + } else if (qual.test_const()) { + cerr << get_fileline() << ": error: " + << "Property " << class_type->get_prop_name(pidx) + << " is constant in this context." << endl; + des->errors += 1; } lv->set_property(method_name); diff --git a/elaborate.cc b/elaborate.cc index 418206c20..204af613d 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -4883,6 +4883,13 @@ static void elaborate_classes(Design*des, NetScope*scope, ; cur != classes.end() ; ++ cur) { netclass_t*use_class = scope->find_class(cur->second->pscope_name()); use_class->elaborate(des, cur->second); + + if (use_class->test_for_missing_initializers()) { + cerr << cur->second->get_fileline() << ": error: " + << "Const properties of class " << use_class->get_name() + << " are missing initialization." << endl; + des->errors += 1; + } } } diff --git a/netclass.cc b/netclass.cc index 91636b95d..abf42071a 100644 --- a/netclass.cc +++ b/netclass.cc @@ -43,6 +43,7 @@ bool netclass_t::set_property(perm_string pname, property_qualifier_t qual, ivl_ tmp.name = pname; tmp.qual = qual; tmp.type = ptype; + tmp.initialized_flag = false; property_table_.push_back(tmp); properties_[pname] = property_table_.size()-1; @@ -88,6 +89,31 @@ ivl_type_t netclass_t::get_prop_type(size_t idx) const return property_table_[idx].type; } +bool netclass_t::get_prop_initialized(size_t idx) const +{ + assert(idx < property_table_.size()); + return property_table_[idx].initialized_flag; +} + +void netclass_t::set_prop_initialized(size_t idx) const +{ + assert(idx < property_table_.size()); + assert(! property_table_[idx].initialized_flag); + property_table_[idx].initialized_flag = true; +} + +bool netclass_t::test_for_missing_initializers() const +{ + for (size_t idx = 0 ; idx < property_table_.size() ; idx += 1) { + if (property_table_[idx].initialized_flag) + continue; + if (property_table_[idx].qual.test_const()) + return true; + } + + return false; +} + NetScope*netclass_t::method_from_name(perm_string name) const { NetScope*task = class_scope_->child( hname_t(name) ); diff --git a/netclass.h b/netclass.h index 8aac64583..71cd32d6a 100644 --- a/netclass.h +++ b/netclass.h @@ -57,6 +57,15 @@ class netclass_t : public ivl_type_s { property_qualifier_t get_prop_qual(size_t idx) const; ivl_type_t get_prop_type(size_t idx) const; + // These methods are used by the elaborator to note the + // initializer for constant properties. Properties start out + // as not initialized, and when elaboration detects an + // assignment to the property, it is marked initialized. + bool get_prop_initialized(size_t idx) const; + void set_prop_initialized(size_t idx) const; + + bool test_for_missing_initializers(void) const; + // Map the name of a property to its index. int property_idx_from_name(perm_string pname) const; @@ -84,6 +93,7 @@ class netclass_t : public ivl_type_s { perm_string name; property_qualifier_t qual; ivl_type_s* type; + mutable bool initialized_flag; }; std::vector property_table_; diff --git a/parse.y b/parse.y index bc120c050..32548fb11 100644 --- a/parse.y +++ b/parse.y @@ -581,7 +581,8 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type struct_data_type %type class_item_qualifier property_qualifier -%type property_qualifier_list property_qualifier_opt +%type class_item_qualifier_list property_qualifier_list +%type class_item_qualifier_opt property_qualifier_opt %type random_qualifier %type range range_opt variable_dimension @@ -695,6 +696,7 @@ class_identifier // lexor detects the name as a type. perm_string name = lex_strings.make($1); class_type_t*tmp = new class_type_t(name); + FILE_NAME(tmp, @1); pform_set_typedef(name, tmp); delete[]$1; $$ = tmp; @@ -793,6 +795,9 @@ class_item /* IEEE1800-2005: A.1.8 */ | property_qualifier_opt data_type list_of_variable_decl_assignments ';' { pform_class_property(@2, $1, $2, $3); } + | K_const class_item_qualifier_opt data_type list_of_variable_decl_assignments ';' + { pform_class_property(@1, $2 | property_qualifier_t::make_const(), $3, $4); } + /* Class methods... */ | method_qualifier_opt task_declaration @@ -837,6 +842,16 @@ class_item_qualifier /* IEEE1800-2005 A.1.8 */ | K_local { $$ = property_qualifier_t::make_local(); } ; +class_item_qualifier_list + : class_item_qualifier_list class_item_qualifier { $$ = $1 | $2; } + | class_item_qualifier { $$ = $1; } + ; + +class_item_qualifier_opt + : class_item_qualifier_list { $$ = $1; } + | { $$ = property_qualifier_t::make_none(); } + ; + class_new /* IEEE1800-2005 A.2.4 */ : K_new '(' ')' { PENewClass*tmp = new PENewClass; @@ -2056,6 +2071,7 @@ type_declaration // lexor detects the name as a type. perm_string name = lex_strings.make($3); class_type_t*tmp = new class_type_t(name); + FILE_NAME(tmp, @3); pform_set_typedef(name, tmp); delete[]$3; } @@ -2070,6 +2086,7 @@ type_declaration // lexor detects the name as a type. perm_string name = lex_strings.make($2); class_type_t*tmp = new class_type_t(name); + FILE_NAME(tmp, @2); pform_set_typedef(name, tmp); delete[]$2; } diff --git a/property_qual.h b/property_qual.h index df02c7080..aaaa37b86 100644 --- a/property_qual.h +++ b/property_qual.h @@ -39,6 +39,9 @@ class property_qualifier_t { static inline property_qualifier_t make_randc() { property_qualifier_t res; res.mask_ = 16; return res; } + static inline property_qualifier_t make_const() + { property_qualifier_t res; res.mask_ = 32; return res; } + inline property_qualifier_t operator | (property_qualifier_t r) { property_qualifier_t res; res.mask_ = mask_ | r.mask_; return res; } @@ -48,6 +51,7 @@ class property_qualifier_t { inline bool test_local() const { return mask_ & 4; } inline bool test_rand() const { return mask_ & 8; } inline bool test_randc() const { return mask_ & 16; } + inline bool test_const() const { return mask_ & 32; } private: int mask_; From 5326790932a2312c35d22c52f4b533a4e3ec5e38 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 2 Jul 2013 19:41:58 -0700 Subject: [PATCH 29/30] Add support for class static properties. Static properties are like variables in a named scope. Detect these variables during elaboration so that the code generator just sees them as variables. --- PExpr.h | 6 +++--- elab_expr.cc | 21 +++++++++++++++++++++ elab_lval.cc | 28 +++++++++++++++++++--------- elab_sig.cc | 19 +++++++++++++++++++ elaborate.cc | 21 ++++++++++++++++++++- netclass.cc | 5 +++++ netclass.h | 6 ++++++ pform_pclass.cc | 15 +++++---------- pform_types.h | 5 +++++ 9 files changed, 103 insertions(+), 23 deletions(-) diff --git a/PExpr.h b/PExpr.h index c19657cff..a7dd0701a 100644 --- a/PExpr.h +++ b/PExpr.h @@ -387,9 +387,9 @@ class PEIdent : public PExpr { bool elaborate_lval_net_idx_(Design*, NetScope*, NetAssign_*, index_component_t::ctype_t, bool need_const_idx) const; - bool elaborate_lval_net_class_member_(Design*, NetScope*, - NetAssign_*, - const perm_string&) const; + NetAssign_*elaborate_lval_net_class_member_(Design*, NetScope*, + NetNet*, + const perm_string&) const; bool elaborate_lval_net_packed_member_(Design*, NetScope*, NetAssign_*, const perm_string&) const; diff --git a/elab_expr.cc b/elab_expr.cc index 68f19b24c..f2dbcc0d1 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1759,6 +1759,17 @@ static NetExpr* check_for_struct_members(const LineInfo*li, return sel; } +static NetExpr* class_static_property_expression(const LineInfo*li, + const netclass_t*class_type, + perm_string name) +{ + NetNet*sig = class_type->find_static_property(name); + ivl_assert(*li, sig); + NetESignal*expr = new NetESignal(sig); + expr->set_line(*li); + return expr; +} + static NetExpr* check_for_class_property(const LineInfo*li, Design*des, NetScope*scope, NetNet*net, @@ -1791,6 +1802,12 @@ static NetExpr* check_for_class_property(const LineInfo*li, des->errors += 1; } + if (qual.test_static()) { + perm_string prop_name = lex_strings.make(class_type->get_prop_name(pidx)); + return class_static_property_expression(li, class_type, + prop_name); + } + NetEProperty*tmp = new NetEProperty(net, comp.name); tmp->set_line(*li); return tmp; @@ -2888,6 +2905,10 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope, des->errors += 1; } + if (qual.test_static()) { + return class_static_property_expression(this, class_type, member_name); + } + NetEProperty*tmp = new NetEProperty(this_net, member_name); tmp->set_line(*this); return tmp; diff --git a/elab_lval.cc b/elab_lval.cc index 3c5c8011e..f4bc96e6b 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -256,8 +256,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, } if (reg->class_type() && !method_name.nil() && gn_system_verilog()) { - NetAssign_*lv = new NetAssign_(reg); - elaborate_lval_net_class_member_(des, use_scope, lv, method_name); + NetAssign_*lv = elaborate_lval_net_class_member_(des, use_scope, reg, method_name); return lv; } @@ -846,17 +845,16 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, return true; } -bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope, - NetAssign_*lv, - const perm_string&method_name) const +NetAssign_* PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope, + NetNet*sig, const perm_string&method_name) const { if (debug_elaborate) { cerr << get_fileline() << ": elaborate_lval_net_class_member_: " << "l-value is property " << method_name - << " of " << lv->sig()->name() << "." << endl; + << " of " << sig->name() << "." << endl; } - const netclass_t*class_type = lv->sig()->class_type(); + const netclass_t*class_type = sig->class_type(); ivl_assert(*this, class_type); /* Make sure the property is really present in the class. If @@ -866,7 +864,7 @@ bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope, cerr << get_fileline() << ": error: Class " << class_type->get_name() << " does not have a property " << method_name << "." << endl; des->errors += 1; - return false; + return 0; } property_qualifier_t qual = class_type->get_prop_qual(pidx); @@ -877,6 +875,17 @@ bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope, << " (scope=" << scope_path(scope) << ")" << endl; des->errors += 1; + } else if (qual.test_static()) { + + // Special case: this is a static property. Ignore the + // "this" sig and use the property itself, which is not + // part of the sig, as the l-value. + NetNet*psig = class_type->find_static_property(method_name); + ivl_assert(*this, psig); + + NetAssign_*lv = new NetAssign_(psig); + return lv; + } else if (qual.test_const()) { cerr << get_fileline() << ": error: " << "Property " << class_type->get_prop_name(pidx) @@ -884,6 +893,7 @@ bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope, des->errors += 1; } + NetAssign_*lv = new NetAssign_(sig); lv->set_property(method_name); ivl_type_t ptype = class_type->get_prop_type(pidx); @@ -898,7 +908,7 @@ bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope, } } - return true; + return lv; } diff --git a/elab_sig.cc b/elab_sig.cc index b9701ebdf..70934d9b9 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -314,6 +314,25 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const void netclass_t::elaborate_sig(Design*des, PClass*pclass) { + for (map::iterator cur = pclass->type->properties.begin() + ; cur != pclass->type->properties.end() ; ++ cur) { + + if (! cur->second.qual.test_static()) + continue; + + if (debug_elaborate) { + cerr << pclass->get_fileline() << ": netclass_t::elaborate_sig: " + << "Elaborate static property " << cur->first + << " as signal in scope " << scope_path(class_scope_) + << "." << endl; + } + + list nil_list; + ivl_type_t use_type = cur->second.type->elaborate_type(des, class_scope_); + NetNet*sig = new NetNet(class_scope_, cur->first, NetNet::REG, + nil_list, use_type); + } + for (map::iterator cur = pclass->funcs.begin() ; cur != pclass->funcs.end() ; ++ cur) { if (debug_elaborate) { diff --git a/elaborate.cc b/elaborate.cc index 204af613d..3abe21e21 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -2361,11 +2361,17 @@ NetProc* PAssign::elaborate_compressed_(Design*des, NetScope*scope) const return cur; } +/* + * Assignments within program blocks can only write to certain types + * of variables. We can only write to: + * - variables in a program block + * - static properties of a class + */ static bool lval_not_program_variable(const NetAssign_*lv) { while (lv) { NetScope*sig_scope = lv->sig()->scope(); - if (! sig_scope->program_block()) + if (! sig_scope->program_block() && sig_scope->type()!=NetScope::CLASS) return true; lv = lv->more; @@ -4969,6 +4975,19 @@ bool Module::elaborate(Design*des, NetScope*scope) const */ void netclass_t::elaborate(Design*des, PClass*pclass) { + if (! pclass->type->initialize_static.empty()) { + std::vector&stmt_list = pclass->type->initialize_static; + NetBlock*stmt = new NetBlock(NetBlock::SEQU, 0); + for (size_t idx = 0 ; idx < stmt_list.size() ; idx += 1) { + NetProc*tmp = stmt_list[idx]->elaborate(des, class_scope_); + if (tmp == 0) continue; + stmt->append(tmp); + } + NetProcTop*top = new NetProcTop(class_scope_, IVL_PR_INITIAL, stmt); + top->set_line(*pclass); + des->add_process(top); + } + for (map::iterator cur = pclass->funcs.begin() ; cur != pclass->funcs.end() ; ++ cur) { if (debug_elaborate) { diff --git a/netclass.cc b/netclass.cc index abf42071a..61f876155 100644 --- a/netclass.cc +++ b/netclass.cc @@ -122,6 +122,11 @@ NetScope*netclass_t::method_from_name(perm_string name) const } +NetNet* netclass_t::find_static_property(perm_string name) const +{ + NetNet*tmp = class_scope_->find_signal(name); +} + bool netclass_t::test_scope_is_method(const NetScope*scope) const { while (scope && scope != class_scope_) { diff --git a/netclass.h b/netclass.h index 71cd32d6a..56039a56c 100644 --- a/netclass.h +++ b/netclass.h @@ -27,6 +27,7 @@ # include class Design; +class NetNet; class NetScope; class PClass; @@ -72,6 +73,11 @@ class netclass_t : public ivl_type_s { // The task method scopes from the method name. NetScope*method_from_name(perm_string mname) const; + // Find the elaborated signal (NetNet) for a static + // property. Search by name. The signal is created by the + // elaborate_sig pass. + NetNet*find_static_property(perm_string name) const; + // Test if this scope is a method within the class. This is // used to check scope for handling data protection keywords // "local" and "protected". diff --git a/pform_pclass.cc b/pform_pclass.cc index 05907aceb..663da18a2 100644 --- a/pform_pclass.cc +++ b/pform_pclass.cc @@ -41,15 +41,6 @@ void pform_class_property(const struct vlltype&loc, { assert(pform_cur_class); - if (property_qual.test_static()) { - // I think the thing to do with static properties is to - // make them PWires directly in the PClass scope. They - // are wires like program/modules wires, and not - // instance members. - VLerror(loc, "sorry: static class properties not implemented."); - return; - } - // Add the non-static properties to the class type // object. Unwind the list of names to make a map of name to // type. @@ -72,7 +63,11 @@ void pform_class_property(const struct vlltype&loc, FILE_NAME(lval, loc); PAssign*tmp = new PAssign(lval, rval); FILE_NAME(tmp, loc); - pform_cur_class->type->initialize.push_back(tmp); + + if (property_qual.test_static()) + pform_cur_class->type->initialize_static.push_back(tmp); + else + pform_cur_class->type->initialize.push_back(tmp); } } } diff --git a/pform_types.h b/pform_types.h index bf657a474..6598f7d26 100644 --- a/pform_types.h +++ b/pform_types.h @@ -233,6 +233,11 @@ struct class_type_t : public data_type_t { // the expression that is assigned. std::vector initialize; + // This is an ordered list of property initializers for static + // properties. These are run in a synthetic "initial" block + // without waiting for any constructor. + std::vector initialize_static; + ivl_type_s* elaborate_type(Design*, NetScope*) const; }; From bb1d26f4f711f8b640088a47e32f483b52715ae2 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 3 Jul 2013 20:07:58 -0700 Subject: [PATCH 30/30] Fix warning/error finding static properties. --- netclass.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/netclass.cc b/netclass.cc index 61f876155..7f2fb97d3 100644 --- a/netclass.cc +++ b/netclass.cc @@ -125,6 +125,7 @@ NetScope*netclass_t::method_from_name(perm_string name) const NetNet* netclass_t::find_static_property(perm_string name) const { NetNet*tmp = class_scope_->find_signal(name); + return tmp; } bool netclass_t::test_scope_is_method(const NetScope*scope) const