From 169228ad0fdafe9754bae22bcd66e0a19cf79140 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 10 Jun 2015 18:41:51 +0200 Subject: [PATCH] vhdlpp: Refactored the way of handling standard VHDL library functions. --- vhdlpp/Makefile.in | 2 +- vhdlpp/entity.h | 11 +- vhdlpp/expression_elaborate.cc | 130 +++---------------- vhdlpp/expression_emit.cc | 110 ++-------------- vhdlpp/library.cc | 33 +++-- vhdlpp/main.cc | 3 + vhdlpp/parse.y | 2 + vhdlpp/scope.cc | 3 +- vhdlpp/sequential_elaborate.cc | 1 - vhdlpp/std_funcs.cc | 226 +++++++++++++++++++++++++++++++++ vhdlpp/std_funcs.h | 34 +++++ vhdlpp/subprogram.cc | 13 +- vhdlpp/subprogram.h | 43 ++++++- vhdlpp/subprogram_emit.cc | 8 ++ vhdlpp/vtype.h | 23 ++-- 15 files changed, 399 insertions(+), 243 deletions(-) create mode 100644 vhdlpp/std_funcs.cc create mode 100644 vhdlpp/std_funcs.h diff --git a/vhdlpp/Makefile.in b/vhdlpp/Makefile.in index ce796c588..e9d36b68b 100644 --- a/vhdlpp/Makefile.in +++ b/vhdlpp/Makefile.in @@ -57,7 +57,7 @@ LIBS = @LIBS@ @EXTRALIBS@ M = StringHeap.o LineInfo.o -O = main.o architec.o compiler.o entity.o \ +O = main.o architec.o compiler.o entity.o std_funcs.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 \ diff --git a/vhdlpp/entity.h b/vhdlpp/entity.h index 5e183d1a5..ed7babdf1 100644 --- a/vhdlpp/entity.h +++ b/vhdlpp/entity.h @@ -34,7 +34,16 @@ class Expression; class InterfacePort : public LineInfo { public: - InterfacePort() { mode = PORT_NONE; type=0; expr=0; } + InterfacePort(port_mode_t mod = PORT_NONE, + perm_string nam = empty_perm_string, + const VType*typ = NULL, + Expression*exp = NULL) + : mode(mod), name(nam), type(typ), expr(exp) + {} + + InterfacePort(const VType*typ) + : mode(PORT_NONE), type(typ), expr(NULL) + {} // Port direction from the source code. port_mode_t mode; diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index c8f014f05..919331548 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -738,53 +738,22 @@ int ExpConditional::case_t::elaborate_expr(Entity*ent, ScopeBase*scope, const VT return errors; } -const VType*ExpFunc::probe_type(Entity*ent, ScopeBase*scope) const +const VType*ExpFunc::probe_type(Entity*, ScopeBase*scope) const { - if(name_ == "integer") - return &primitive_INTEGER; + SubprogramHeader*prog = def_; - if(name_ == "unsigned" || name_ == "resize") { - if(argv_.empty()) - return NULL; - - const VType*type = argv_[0]->probe_type(ent, scope); - if(!type) - return NULL; - - int msb = type->get_width(scope) - 1; - ivl_assert(*this, msb >= 0); - - // Determine the sign - bool sign = false; - if(name_ == "resize") { - if(const VTypeArray*arr = dynamic_cast(type)) - sign = arr->signed_vector(); - } - - return new VTypeArray(&primitive_BIT, msb, 0, sign); + if(!prog) { + prog = scope->find_subprogram(name_); } - if(name_ == "std_logic_vector" || name_ == "conv_std_logic_vector") { - if(argv_.empty()) - return NULL; + if(!prog) + prog = library_find_subprogram(name_); - const VType*type = argv_[0]->probe_type(ent, scope); - if(!type) - return NULL; - - int msb = type->get_width(scope) - 1; - - return new VTypeArray(&primitive_STDLOGIC, msb, 0); + if(!prog) { + cerr << get_fileline() << ": sorry: VHDL function " << name_ << " not yet implemented" << endl; + ivl_assert(*this, false); } - SubprogramHeader*prog = scope->find_subprogram(name_); - - if(!prog) - prog = library_find_subprogram(name_); - - if(!prog) - return NULL; - return prog->peek_return_type(); } @@ -812,86 +781,25 @@ int ExpFunc::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) errors += argv_[idx]->elaborate_expr(ent, scope, tmp); } - if(def_ && def_->unbounded()) { + // SystemVerilog functions work only with defined size data types, therefore + // if header does not specify argument or return type size, create a function + // instance that work with this particular size. + if(def_ && !def_->is_std() && def_->unbounded()) { def_ = prog->make_instance(argv_, scope); name_ = def_->name(); } + if(!def_) { + cerr << get_fileline() << ": error: could not find function " << name_ << endl; + ++errors; + } + return errors; } const VType* ExpFunc::fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*) const { - // Built-in functions - if(name_ == "to_integer" || name_ == "unsigned" || name_ == "integer") { - ivl_assert(*this, argv_.size() == 1); - - const VType*type = argv_[0]->probe_type(ent, scope); - ivl_assert(*this, type); - - // Determine the sign - bool sign = false; - - if(name_ == "integer") { - sign = true; - } else if(name_ == "to_integer") { - if(const VTypeArray*arr = dynamic_cast(type)) - sign = arr->signed_vector(); - } - - return new VTypeArray(&primitive_BIT, type->get_width(scope), 0, sign); - } - - if(name_ == "to_unsigned" || name_ == "std_logic_vector" || - name_ == "conv_std_logic_vector" || name_ == "resize") - { - ivl_assert(*this, argv_.size() == 2); - - // Determine the sign - bool sign = false; - const VType*element = &primitive_STDLOGIC; - - if(name_ == "resize") { - const VType*type = argv_[0]->probe_type(ent, scope); - ivl_assert(*this, type); - - if(const VTypeArray*arr = dynamic_cast(type)) - { - sign = arr->signed_vector(); - element = arr->element_type(); - } - } else if(name_ == "to_unsigned") { - element = &primitive_BIT; - } - - int64_t width = 0; - bool evaluated = argv_[1]->evaluate(scope, width); - ivl_assert(*this, evaluated); - - return new VTypeArray(element, width, 0, sign); - } - - if(name_ == "and_reduce" || name_ == "or_reduce") { - ivl_assert(*this, argv_.size() == 1); - const VType*element = &primitive_STDLOGIC; - return new VTypeArray(element, 0, 0, false); - } - - // Other cases - SubprogramHeader*prog = def_; - - if(!prog) { - ivl_assert(*this, scope); - prog = scope->find_subprogram(name_); - } - - if(!prog) - prog = library_find_subprogram(name_); - - cerr << get_fileline() << ": sorry: VHDL function " << name_ << " not yet implemented" << endl; - ivl_assert(*this, prog); - - return def_->peek_return_type(); + return probe_type(ent, scope); } const VType* ExpInteger::probe_type(Entity*, ScopeBase*) const diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 99b0fc886..281ad01ef 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -23,7 +23,7 @@ # include "vtype.h" # include "architec.h" # include "package.h" -# include "subprogram.h" +# include "std_funcs.h" # include "parse_types.h" # include # include @@ -567,103 +567,21 @@ int ExpFunc::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; - if (name_ == "unsigned" && argv_.size() == 1) { - // Handle the special case that this is a cast to - // unsigned. This function is brought in as part of the - // std numeric library, but we interpret it as the same - // as the $unsigned function. - out << "$unsigned("; - errors += argv_[0]->emit(out, ent, scope); - out << ")"; + ivl_assert(*this, def_); - } else if (name_ == "integer" && argv_.size() == 1) { - out << "$signed("; - errors += argv_[0]->emit(out, ent, scope); - out << ")"; + // If this function has an elaborated definition, 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. + const Package*pkg = dynamic_cast (def_->get_parent()); + if (pkg != 0) + out << "\\" << pkg->name() << " ::"; - } else if (name_ == "to_integer" && argv_.size() == 1) { - bool signed_flag = false; - - // to_integer converts unsigned to natural - // signed to integer - // try to determine the converted type - const VType*type = argv_[0]->probe_type(ent, scope); - const VTypeArray*array = dynamic_cast(type); - - if(array) - signed_flag = array->signed_vector(); - else - cerr << get_fileline() << ": sorry: Could not determine the " - << "expression sign. Output may be erroneous." << endl; - - out << (signed_flag ? "$signed(" : "$unsigned("); - errors += argv_[0]->emit(out, ent, scope); - out << ")"; - - } else if (name_ == "std_logic_vector" && argv_.size() == 1) { - // Special case: The std_logic_vector function casts its - // argument to std_logic_vector. Internally, we don't - // have to do anything for that to work. - out << "("; - errors += argv_[0]->emit(out, ent, scope); - out << ")"; - - } else if (name_ == "to_unsigned" && argv_.size() == 2) { - - out << "$ivlh_to_unsigned("; - errors += argv_[0]->emit(out, ent, scope); - out << ", "; - errors += argv_[1]->emit(out, ent, scope); - out << ")"; - - } else if ((name_ == "conv_std_logic_vector" || name_ == "resize") && - argv_.size() == 2) { - int64_t use_size; - bool rc = argv_[1]->evaluate(ent, scope, use_size); - ivl_assert(*this, rc); - out << use_size << "'("; - errors += argv_[0]->emit(out, ent, scope); - out << ")"; - - } else if (name_ == "rising_edge" && argv_.size() == 1) { - out << "$ivlh_rising_edge("; - errors += argv_[0]->emit(out, ent, scope); - out << ")"; - - } else if (name_ == "falling_edge" && argv_.size() == 1) { - out << "$ivlh_falling_edge("; - errors += argv_[0]->emit(out, ent, scope); - out << ")"; - - } else if (name_ == "and_reduce" && argv_.size() == 1) { - out << "&("; - errors += argv_[0]->emit(out, ent, scope); - out << ")"; - - } else if (name_ == "or_reduce" && argv_.size() == 1) { - out << "|("; - errors += argv_[0]->emit(out, ent, scope); - out << ")"; - - } else { - // If this function has an elaborated definition, 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 << ", "; - errors += argv_[idx]->emit(out, ent, scope); - } - out << ")"; - } + errors += def_->emit_name(argv_, out, ent, scope); + out << " ("; + def_->emit_args(argv_, out, ent, scope); + out << ")"; return errors; } diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index e6fee4d82..be3649005 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -305,9 +305,7 @@ static void import_ieee_use_std_logic_1164(ActiveScope*res, perm_string name) bool all_flag = name=="all"; if (all_flag || name == "std_logic_vector") { - vector dims (1); - res->use_name(perm_string::literal("std_logic_vector"), - new VTypeArray(&primitive_STDLOGIC, dims, false)); + res->use_name(perm_string::literal("std_logic_vector"), &primitive_STDLOGIC_VECTOR); } } @@ -393,22 +391,23 @@ const VTypePrimitive primitive_STDLOGIC(VTypePrimitive::STDLOGIC, true); const VTypePrimitive primitive_CHARACTER(VTypePrimitive::CHARACTER); const VTypePrimitive primitive_TIME(VTypePrimitive::TIME); -static const VTypeArray primitive_BIT_VECTOR(&primitive_BIT, vector (1)); -static const VTypeArray primitive_BOOL_VECTOR(&primitive_BOOLEAN, vector (1)); -static const VTypeArray primitive_STRING(&primitive_CHARACTER, vector (1)); +const VTypeArray primitive_BIT_VECTOR(&primitive_BIT, vector (1)); +const VTypeArray primitive_BOOL_VECTOR(&primitive_BOOLEAN, vector (1)); +const VTypeArray primitive_STDLOGIC_VECTOR(&primitive_STDLOGIC, vector (1)); +const VTypeArray primitive_STRING(&primitive_CHARACTER, vector (1)); void generate_global_types(ActiveScope*res) { - 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("real"), &primitive_REAL); - 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_BIT_VECTOR); - res->use_name(perm_string::literal("string"), &primitive_STRING); - res->use_name(perm_string::literal("natural"), &primitive_NATURAL); - res->use_name(perm_string::literal("time"), &primitive_TIME); + res->use_name(perm_string::literal("boolean"), &primitive_BOOLEAN); + res->use_name(perm_string::literal("bit"), &primitive_BIT); + res->use_name(perm_string::literal("bit_vector"), &primitive_BIT_VECTOR); + res->use_name(perm_string::literal("integer"), &primitive_INTEGER); + res->use_name(perm_string::literal("real"), &primitive_REAL); + 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("string"), &primitive_STRING); + res->use_name(perm_string::literal("natural"), &primitive_NATURAL); + res->use_name(perm_string::literal("time"), &primitive_TIME); } void emit_std_types(ostream&out) @@ -423,12 +422,12 @@ bool is_global_type(perm_string name) { if (name == "boolean") return true; if (name == "bit") return true; + if (name == "bit_vector") return true; if (name == "integer") return true; if (name == "real") return true; if (name == "std_logic") return true; if (name == "std_logic_vector") return true; if (name == "character") return true; - if (name == "bit_vector") return true; if (name == "string") return true; if (name == "natural") return true; if (name == "signed") return true; diff --git a/vhdlpp/main.cc b/vhdlpp/main.cc index 418e73daa..5d4ad7951 100644 --- a/vhdlpp/main.cc +++ b/vhdlpp/main.cc @@ -76,6 +76,7 @@ const char NOTICE[] = # include "compiler.h" # include "library.h" +# include "std_funcs.h" # include "parse_api.h" # include "vtype.h" # include @@ -184,6 +185,8 @@ int main(int argc, char*argv[]) library_set_work_path(work_path); preload_global_types(); + preload_std_funcs(); + int errors = 0; for (int idx = optind ; idx < argc ; idx += 1) { diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 3536a6660..f31c35d17 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -39,6 +39,7 @@ # include "package.h" # include "vsignal.h" # include "vtype.h" +# include "std_funcs.h" # include # include # include @@ -146,6 +147,7 @@ void parser_cleanup(void) { delete_design_entities(); delete_global_scope(); + delete_std_funcs(); lex_strings.cleanup(); } diff --git a/vhdlpp/scope.cc b/vhdlpp/scope.cc index c6f96a245..3a7fdc4d7 100644 --- a/vhdlpp/scope.cc +++ b/vhdlpp/scope.cc @@ -22,6 +22,7 @@ # include "package.h" # include "subprogram.h" # include "entity.h" +# include "std_funcs.h" # include # include # include @@ -185,7 +186,7 @@ SubprogramHeader* ScopeBase::find_subprogram(perm_string name) const if (cur != use_subprograms_.end()) return cur->second; - return 0; + return find_std_subprogram(name); } const VTypeEnum* ScopeBase::is_enum_name(perm_string name) const diff --git a/vhdlpp/sequential_elaborate.cc b/vhdlpp/sequential_elaborate.cc index 80e7b2584..4a574c2e5 100644 --- a/vhdlpp/sequential_elaborate.cc +++ b/vhdlpp/sequential_elaborate.cc @@ -149,7 +149,6 @@ int SignalSeqAssignment::elaborate(Entity*ent, ScopeBase*scope) // Elaborate the r-value expressions. for (list::iterator cur = waveform_.begin() ; cur != waveform_.end() ; ++cur) { - errors += (*cur)->elaborate_expr(ent, scope, lval_type); } diff --git a/vhdlpp/std_funcs.cc b/vhdlpp/std_funcs.cc new file mode 100644 index 000000000..e93debc2d --- /dev/null +++ b/vhdlpp/std_funcs.cc @@ -0,0 +1,226 @@ +/* + * Copyright CERN 2015 + * @author Maciej Suminski (maciej.suminski@cern.ch) + * + * 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 "std_funcs.h" +#include "vtype.h" +#include "scope.h" + +static std::map std_subprograms; + +// Special case: to_integer function +static class SubprogramToInteger : public SubprogramHeader { + public: + SubprogramToInteger() + : SubprogramHeader(perm_string::literal("to_integer"), NULL, &primitive_REAL) { + ports_ = new std::list(); + ports_->push_back(new InterfacePort(&primitive_INTEGER)); + } + + bool is_std() const { return true; } + + int emit_name(const std::vector&argv, + std::ostream&out, Entity*ent, ScopeBase*scope) const { + bool signed_flag = false; + + // to_integer converts unsigned to natural + // signed to integer + // try to determine the converted type + const VType*type = argv[0]->probe_type(ent, scope); + const VTypeArray*array = dynamic_cast(type); + + if(array) { + signed_flag = array->signed_vector(); + } else { + cerr << get_fileline() << ": sorry: Could not determine the " + << "expression sign. Output may be erroneous." << endl; + return 1; + } + + out << (signed_flag ? "$signed" : "$unsigned"); + return 0; + } +}*fn_to_integer; + +// Special case: size casting (e.g. conv_std_logic_vector() / resize()). +static class SubprogramSizeCast : public SubprogramHeader { + public: + SubprogramSizeCast(perm_string nam) + : SubprogramHeader(nam, NULL, &primitive_STDLOGIC_VECTOR) { + ports_ = new std::list(); + ports_->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR)); + ports_->push_back(new InterfacePort(&primitive_INTEGER)); + } + + bool is_std() const { return true; } + + int emit_name(const std::vector&argv, + std::ostream&out, Entity*ent, ScopeBase*scope) const { + int64_t use_size; + bool rc = argv[1]->evaluate(ent, scope, use_size); + + if(!rc) { + cerr << get_fileline() << ": sorry: Could not evaluate the " + << "expression size. Size casting impossible." << endl; + return 1; + } + + out << use_size << "'"; + return 0; + } + + int emit_args(const std::vector&argv, + std::ostream&out, Entity*ent, ScopeBase*scope) const { + + return argv[0]->emit(out, ent, scope); + } +}*fn_conv_std_logic_vector, *fn_resize; + +static SubprogramBuiltin*fn_std_logic_vector; +static SubprogramBuiltin*fn_to_unsigned; +static SubprogramBuiltin*fn_unsigned; +static SubprogramBuiltin*fn_integer; + +static SubprogramBuiltin*fn_rising_edge; +static SubprogramBuiltin*fn_falling_edge; + +static SubprogramBuiltin*fn_and_reduce; +static SubprogramBuiltin*fn_or_reduce; + +void preload_std_funcs(void) +{ + /* numeric_std library + * function unsigned + */ + std::list*fn_unsigned_args = new std::list(); + fn_unsigned_args->push_back(new InterfacePort(&primitive_INTEGER)); + fn_unsigned = new SubprogramBuiltin(perm_string::literal("unsigned"), + perm_string::literal("$unsigned"), + fn_unsigned_args, &primitive_UNSIGNED); + std_subprograms[fn_unsigned->name()] = fn_unsigned; + + /* function integer + */ + std::list*fn_integer_args = new std::list(); + fn_integer_args->push_back(new InterfacePort(&primitive_INTEGER)); + fn_integer = new SubprogramBuiltin(perm_string::literal("integer"), + perm_string::literal("$signed"), + fn_integer_args, &primitive_INTEGER); + std_subprograms[fn_integer->name()] = fn_integer; + + /* function std_logic_vector + Special case: The std_logic_vector function casts its + argument to std_logic_vector. Internally, we don't + have to do anything for that to work. + */ + std::list*fn_std_logic_vector_args = new std::list(); + fn_std_logic_vector_args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR)); + fn_std_logic_vector = new SubprogramBuiltin(perm_string::literal("std_logic_vector"), + empty_perm_string, + fn_std_logic_vector_args, &primitive_STDLOGIC_VECTOR); + std_subprograms[fn_std_logic_vector->name()] = fn_std_logic_vector; + + /* function resize + */ + fn_resize = new SubprogramSizeCast(perm_string::literal("resize")); + std_subprograms[fn_resize->name()] = fn_resize; + + /* function conv_std_logic_vector + */ + fn_conv_std_logic_vector = new SubprogramSizeCast(perm_string::literal("conv_std_logic_vector")); + std_subprograms[fn_conv_std_logic_vector->name()] = fn_conv_std_logic_vector; + + /* numeric_bit library + * function to_integer (arg: unsigned) return natural; + * function to_integer (arg: signed) return integer; + */ + fn_to_integer = new SubprogramToInteger(); + std_subprograms[fn_to_integer->name()] = fn_to_integer; + + /* std_logic_1164 library + * function rising_edge (signal s : std_ulogic) return boolean; + */ + std::list*fn_rising_edge_args = new std::list(); + fn_rising_edge_args->push_back(new InterfacePort(&primitive_STDLOGIC)); + fn_rising_edge = new SubprogramBuiltin(perm_string::literal("rising_edge"), + perm_string::literal("$ivlh_rising_edge"), + fn_rising_edge_args, &primitive_BOOLEAN); + std_subprograms[fn_rising_edge->name()] = fn_rising_edge; + + /* std_logic_1164 library + * function falling_edge (signal s : std_ulogic) return boolean; + */ + std::list*fn_falling_edge_args = new std::list(); + fn_falling_edge_args->push_back(new InterfacePort(&primitive_STDLOGIC)); + fn_falling_edge = new SubprogramBuiltin(perm_string::literal("falling_edge"), + perm_string::literal("$ivlh_falling_edge"), + fn_falling_edge_args, &primitive_BOOLEAN); + std_subprograms[fn_falling_edge->name()] = fn_falling_edge; + + /* reduce_pack library + * function or_reduce(arg : std_logic_vector) return std_logic; + */ + std::list*fn_or_reduce_args = new std::list(); + fn_or_reduce_args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR)); + fn_or_reduce = new SubprogramBuiltin(perm_string::literal("or_reduce"), + perm_string::literal("|"), + fn_or_reduce_args, &primitive_STDLOGIC); + std_subprograms[fn_or_reduce->name()] = fn_or_reduce; + + /* reduce_pack library + * function and_reduce(arg : std_logic_vector) return std_logic; + */ + std::list*fn_and_reduce_args = new std::list(); + fn_and_reduce_args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR)); + fn_and_reduce = new SubprogramBuiltin(perm_string::literal("and_reduce"), + perm_string::literal("&"), + fn_and_reduce_args, &primitive_STDLOGIC); + std_subprograms[fn_and_reduce->name()] = fn_and_reduce; + + /* fixed_pkg library + * function to_unsigned ( + * arg : ufixed; -- fixed point input + * constant size : natural) -- length of output + * return unsigned; + */ + std::list*fn_to_unsigned_args = new std::list(); + fn_to_unsigned_args->push_back(new InterfacePort(&primitive_REAL)); + fn_to_unsigned_args->push_back(new InterfacePort(&primitive_NATURAL)); + fn_to_unsigned = new SubprogramBuiltin(perm_string::literal("to_unsigned"), + perm_string::literal("$ivlh_to_unsigned"), + fn_to_unsigned_args, &primitive_UNSIGNED); + std_subprograms[fn_to_unsigned->name()] = fn_to_unsigned; +} + +void delete_std_funcs() +{ + for(std::map::iterator it = std_subprograms.begin(); + it != std_subprograms.end(); ++it) { + delete it->second; + } +} + +SubprogramHeader*find_std_subprogram(perm_string name) +{ + map::const_iterator cur = std_subprograms.find(name); + if (cur != std_subprograms.end()) + return cur->second; + + return NULL; +} diff --git a/vhdlpp/std_funcs.h b/vhdlpp/std_funcs.h new file mode 100644 index 000000000..c966f6591 --- /dev/null +++ b/vhdlpp/std_funcs.h @@ -0,0 +1,34 @@ +#ifndef IVL_std_funcs_H +#define IVL_std_funcs_H +/* + * Copyright CERN 2015 + * @author Maciej Suminski (maciej.suminski@cern.ch) + * + * 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" + +// Generates subprogram headers for standard VHDL library functions. +void preload_std_funcs(); + +// Destroys subprogram headers for standard VHDL library functions. +void delete_std_funcs(); + +// Returns subprogram header for a requested function or NULL if it does not exist. +SubprogramHeader*find_std_subprogram(perm_string name); + +#endif /* IVL_std_funcs_H */ diff --git a/vhdlpp/subprogram.cc b/vhdlpp/subprogram.cc index aa62eee01..d8e96ed4d 100644 --- a/vhdlpp/subprogram.cc +++ b/vhdlpp/subprogram.cc @@ -82,6 +82,7 @@ SubprogramHeader::SubprogramHeader(perm_string nam, list*ports, SubprogramHeader::~SubprogramHeader() { delete body_; + delete ports_; } bool SubprogramHeader::compare_specification(SubprogramHeader*that) const @@ -170,7 +171,7 @@ void SubprogramHeader::set_body(SubprogramBody*bdy) } SubprogramHeader*SubprogramHeader::make_instance(std::vector arguments, - ScopeBase*scope) { + ScopeBase*scope) const { assert(arguments.size() == ports_->size()); std::list*ports = new std::list; @@ -293,3 +294,13 @@ void SubprogramHeader::write_to_stream(ostream&fd) const fd << ") return "; return_type_->write_to_stream(fd); } + +SubprogramBuiltin::SubprogramBuiltin(perm_string vhdl_name, perm_string sv_name, + std::list*ports, const VType*return_type) + : SubprogramHeader(vhdl_name, ports, return_type), sv_name_(sv_name) +{ +} + +SubprogramBuiltin::~SubprogramBuiltin() +{ +} diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h index d0b05991d..0aa5dbdbc 100644 --- a/vhdlpp/subprogram.h +++ b/vhdlpp/subprogram.h @@ -64,7 +64,7 @@ class SubprogramHeader : public LineInfo { public: SubprogramHeader(perm_string name, std::list*ports, const VType*return_type); - ~SubprogramHeader(); + virtual ~SubprogramHeader(); // Return true if the specification (name, types, ports) // matches this subprogram and that subprogram. @@ -80,16 +80,32 @@ class SubprogramHeader : public LineInfo { // Checks if either return type or parameters are unbounded vectors. bool unbounded() const; - inline SubprogramBody*body() { return body_; } + // Is the subprogram coming from the standard library? + virtual bool is_std() const { return false; } + + inline SubprogramBody*body() const { return body_; } void set_body(SubprogramBody*bdy); - inline perm_string name() { return name_; } + inline perm_string name() const { return name_; } + + // Function name used in the emission step. The main purpose of this + // method is to handle functions offered by standard VHDL libraries. + // Allows to return different function names depending on the arguments + // (think of size casting or signed/unsigned functions). + virtual int emit_name(const std::vector&, + std::ostream&out, Entity*, ScopeBase*) const; + + // Emit arguments for a specific call. It allows to reorder or skip + // some of the arguments if function signature is different in + // SystemVerilog compared to VHDL. + virtual int emit_args(const std::vector&argv, + std::ostream&out, Entity*, ScopeBase*) const; // Creates a new instance of the function that takes arguments of // a different type. It is used to allow VHDL functions that work with // unbounded std_logic_vectors, so there can be a separate instance // for limited length logic vector. - SubprogramHeader*make_instance(std::vector arguments, ScopeBase*scope); + SubprogramHeader*make_instance(std::vector arguments, ScopeBase*scope) const; // Emit header as it would show up in a package. int emit_package(std::ostream&fd) const; @@ -97,7 +113,7 @@ class SubprogramHeader : public LineInfo { void write_to_stream(std::ostream&fd) const; void dump(std::ostream&fd) const; - private: + protected: // Tries to set the return type to a fixed type. VHDL functions that // return std_logic_vectors do not specify its length, as SystemVerilog // demands. @@ -112,4 +128,21 @@ class SubprogramHeader : public LineInfo { const ScopeBase*parent_; }; +// Class to define functions headers defined in the standard VHDL libraries. +class SubprogramBuiltin : public SubprogramHeader +{ + public: + SubprogramBuiltin(perm_string vhdl_name, perm_string sv_name, + std::list*ports, const VType*return_type); + ~SubprogramBuiltin(); + + bool is_std() const { return true; } + + int emit_name(const std::vector&, std::ostream&out, Entity*, ScopeBase*) const; + + private: + // SystemVerilog counterpart function name + perm_string sv_name_; +}; + #endif /* IVL_subprogram_H */ diff --git a/vhdlpp/subprogram_emit.cc b/vhdlpp/subprogram_emit.cc index fde37a178..ae2b23775 100644 --- a/vhdlpp/subprogram_emit.cc +++ b/vhdlpp/subprogram_emit.cc @@ -116,3 +116,11 @@ int SubprogramHeader::emit_args(const std::vector&argv, return errors; } + +int SubprogramBuiltin::emit_name(const std::vector&, + std::ostream&out, Entity*, ScopeBase*) const +{ + // do not escape the names for builtin functions + out << sv_name_; + return 0; +} diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index 0756ff68b..adf4cea12 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -180,15 +180,6 @@ class VTypePrimitive : public VType { bool packed_; }; -extern const VTypePrimitive primitive_BOOLEAN; -extern const VTypePrimitive primitive_BIT; -extern const VTypePrimitive primitive_INTEGER; -extern const VTypePrimitive primitive_NATURAL; -extern const VTypePrimitive primitive_REAL; -extern const VTypePrimitive primitive_STDLOGIC; -extern const VTypePrimitive primitive_CHARACTER; -extern const VTypePrimitive primitive_TIME; - /* * An array is a compound N-dimensional array of element type. The * construction of the array is from an element type and a vector of @@ -391,4 +382,18 @@ class VTypeDef : public VType { const VType*type_; }; +extern const VTypePrimitive primitive_BOOLEAN; +extern const VTypePrimitive primitive_BIT; +extern const VTypePrimitive primitive_INTEGER; +extern const VTypePrimitive primitive_NATURAL; +extern const VTypePrimitive primitive_REAL; +extern const VTypePrimitive primitive_STDLOGIC; +extern const VTypePrimitive primitive_CHARACTER; +extern const VTypePrimitive primitive_TIME; + +extern const VTypeArray primitive_BIT_VECTOR; +extern const VTypeArray primitive_BOOL_VECTOR; +extern const VTypeArray primitive_STDLOGIC_VECTOR; +extern const VTypeArray primitive_STRING; + #endif /* IVL_vtype_H */