diff --git a/eval_tree.cc b/eval_tree.cc index 15bbc96d4..0b373312c 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -2009,6 +2009,12 @@ static bool check_dimension(const NetExpr*dim_expr, long &dim) static bool get_array_info(const NetExpr*arg, long dim, long &left, long &right, bool&defer) { + if (const NetEConstParam*param = dynamic_cast(arg)) { + assert(dim == 1); + left = param->expr_width() - 1; + right = 0; + return false; + } /* The argument must be a signal that has enough dimensions. */ const NetESignal*esig = dynamic_cast(arg); if (esig == 0) return true; diff --git a/parse.y b/parse.y index 5ea8250ab..bc866fea6 100644 --- a/parse.y +++ b/parse.y @@ -4169,6 +4169,9 @@ port_declaration use_type = NetNet::IMPLICIT_REG; } else if (dynamic_cast ($4)) { use_type = NetNet::IMPLICIT_REG; + } else if (enum_type_t*etype = dynamic_cast ($4)) { + if(etype->base_type == IVL_VT_LOGIC) + use_type = NetNet::IMPLICIT_REG; } } ptmp = pform_module_port_reference(name, @2.text, @2.first_line); diff --git a/vhdlpp/Makefile.in b/vhdlpp/Makefile.in index ce796c588..0a0f264d2 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 std_types.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/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index 327457ef1..e734ce1fc 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -195,50 +195,6 @@ 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. - - 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'. diff --git a/vhdlpp/architec_emit.cc b/vhdlpp/architec_emit.cc index d0d3fb1ff..7164f5fad 100644 --- a/vhdlpp/architec_emit.cc +++ b/vhdlpp/architec_emit.cc @@ -101,7 +101,7 @@ int Architecture::emit(ostream&out, Entity*entity) errors += emit_signals(out, entity, this); errors += emit_variables(out, entity, this); - for (map::const_iterator cur = cur_subprograms_.begin() + for (map::const_iterator cur = cur_subprograms_.begin() ; cur != cur_subprograms_.end() ; ++ cur) { // Do not emit unbounded functions, we will just need fixed instances later if(!cur->second->unbounded()) diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index 7c2295718..71ca0abd4 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -150,17 +150,21 @@ void Scope::dump_scope(ostream&out) const } // Dump subprograms out << " -- Imported Subprograms" << endl; - for (map::const_iterator cur = use_subprograms_.begin() + for (map::const_iterator cur = use_subprograms_.begin() ; cur != use_subprograms_.end() ; ++cur) { out << " subprogram " << cur->first << " is" << endl; cur->second->dump(out); + if(cur->second->body()) + cur->second->body()->dump(out); out << " end subprogram " << cur->first << endl; } out << " -- Subprograms from this scope" << endl; - for (map::const_iterator cur = cur_subprograms_.begin() + for (map::const_iterator cur = cur_subprograms_.begin() ; cur != cur_subprograms_.end() ; ++cur) { out << " subprogram " << cur->first << " is" << endl; cur->second->dump(out); + if(cur->second->body()) + cur->second->body()->dump(out); out << " end subprogram " << cur->first << endl; } // Dump component declarations @@ -279,22 +283,14 @@ void ExpCharacter::dump(ostream&out, int indent) const void ExpConditional::dump(ostream&out, int indent) const { out << setw(indent) << "" << "Conditional expression at "<< get_fileline() << endl; - out << setw(indent) << "" << " when:" << endl; - cond_->dump(out, indent+4); - out << setw(indent) << "" << " do:" << endl; - for (list::const_iterator cur = true_clause_.begin() - ; cur != true_clause_.end() ; ++cur) { - (*cur)->dump(out, indent+4); - } - - for (list::const_iterator cur = else_clause_.begin() - ; cur != else_clause_.end() ; ++cur) { + for (list::const_iterator cur = options_.begin() + ; cur != options_.end() ; ++cur) { (*cur)->dump(out, indent); } } -void ExpConditional::else_t::dump(ostream&out, int indent) const +void ExpConditional::case_t::dump(ostream&out, int indent) const { out << setw(indent) << "" << "when:" << endl; if (cond_) cond_->dump(out, indent+4); @@ -475,7 +471,20 @@ ostream& ExpReal::dump_inline(ostream&out) const return out; } -void Subprogram::dump(ostream&fd) const +void SubprogramBody::dump(ostream&fd) const +{ + 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); + } + } +} + +void SubprogramHeader::dump(ostream&fd) const { fd << " " << name_; @@ -501,14 +510,4 @@ void Subprogram::dump(ostream&fd) const 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/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.cc b/vhdlpp/expression.cc index 0e3a0b493..9a0a4185f 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -129,12 +129,21 @@ ExpAggregate::ExpAggregate(std::list*el) elements_[idx++] = el->front(); el->pop_front(); } + delete el; } ExpAggregate::~ExpAggregate() { - for (size_t idx = 0 ; idx < elements_.size() ; idx += 1) - delete elements_[idx]; + for(std::vector::iterator it = elements_.begin(); + it != elements_.end(); ++it) { + delete *it; + } + + for(std::vector::iterator it = aggregate_.begin(); + it != aggregate_.end(); ++it) { + delete it->choice; + delete it->expr; + } } Expression* ExpAggregate::clone() const @@ -301,84 +310,53 @@ void ExpConcat::visit(ExprVisitor& func) } ExpConditional::ExpConditional(Expression*co, list*tru, - list*fal) -: cond_(co) + list*options) { - if (tru) true_clause_.splice(true_clause_.end(), *tru); - if (fal) else_clause_.splice(else_clause_.end(), *fal); + if(co && tru) options_.push_back(new case_t(co, tru)); + if(options) options_.splice(options_.end(), *options); } ExpConditional::~ExpConditional() { - delete cond_; - while (! true_clause_.empty()) { - Expression*tmp = true_clause_.front(); - true_clause_.pop_front(); - delete tmp; - } - while (! else_clause_.empty()) { - else_t*tmp = else_clause_.front(); - else_clause_.pop_front(); + while (!options_.empty()) { + case_t*tmp = options_.front(); + options_.pop_front(); delete tmp; } } Expression*ExpConditional::clone() const { - std::list*new_true_clause = NULL; - if(!true_clause_.empty()) { - new_true_clause = new std::list(); + std::list*new_options = NULL; + if(!options_.empty()) { + new_options = new std::list(); - for(std::list::const_iterator it = true_clause_.begin(); - it != true_clause_.end(); ++it) { - new_true_clause->push_back((*it)->clone()); + for(std::list::const_iterator it = options_.begin(); + it != options_.end(); ++it) { + new_options->push_back(new case_t(**it)); } } - std::list*new_else_clause = NULL; - if(!else_clause_.empty()) { - new_else_clause = new std::list(); - - for(std::list::const_iterator it = else_clause_.begin(); - it != else_clause_.end(); ++it) { - new_else_clause->push_back(new else_t(**it)); - } - } - - return new ExpConditional(cond_->clone(), new_true_clause, new_else_clause); + return new ExpConditional(NULL, NULL, new_options); } void ExpConditional::visit(ExprVisitor& func) { - if(!true_clause_.empty()) { - for(std::list::iterator it = true_clause_.begin(); - it != true_clause_.end(); ++it) { - (*it)->visit(func); - } - } - - if(!else_clause_.empty()) { - for(std::list::iterator it = else_clause_.begin(); - it != else_clause_.end(); ++it) { - std::list& else_clause = (*it)->extract_true_clause(); - - for(std::list::iterator jt = else_clause.begin(); - jt != else_clause.end(); ++jt) { - (*jt)->visit(func); - } - } + for(std::list::iterator it = options_.begin(); + it != options_.end(); ++it) { + (*it)->visit(func); } func(this); } -ExpConditional::else_t::else_t(Expression*cond, std::list*tru) +ExpConditional::case_t::case_t(Expression*cond, std::list*tru) : cond_(cond) { if (tru) true_clause_.splice(true_clause_.end(), *tru); } -ExpConditional::else_t::else_t(const else_t&other) +ExpConditional::case_t::case_t(const case_t&other) : LineInfo(other) { cond_ = other.cond_->clone(); @@ -388,7 +366,7 @@ ExpConditional::else_t::else_t(const else_t&other) } } -ExpConditional::else_t::~else_t() +ExpConditional::case_t::~case_t() { delete cond_; while (! true_clause_.empty()) { @@ -398,6 +376,49 @@ ExpConditional::else_t::~else_t() } } +ExpSelected::ExpSelected(Expression*selector, std::list*options) +: ExpConditional(NULL, NULL, options), selector_(selector) +{ + // Currently condition field contains only value, + // so substitute it with a comparison to create a valid condition + for(std::list::iterator it = options_.begin(); + it != options_.end(); ++it) { + Expression*cond = (*it)->condition(); + + if(cond) + (*it)->set_condition(new ExpRelation(ExpRelation::EQ, selector_->clone(), cond)); + } +} + +ExpSelected::~ExpSelected() +{ +} + +Expression*ExpSelected::clone() const +{ + std::list*new_options = NULL; + if(!options_.empty()) { + new_options = new std::list(); + + for(std::list::const_iterator it = options_.begin(); + it != options_.end(); ++it) { + new_options->push_back(new case_t(**it)); + } + } + + return new ExpSelected(selector_->clone(), new_options); +} + +void ExpConditional::case_t::visit(ExprVisitor& func) +{ + if(cond_) + func(cond_); + + for(std::list::iterator it = true_clause_.begin(); + it != true_clause_.end(); ++it) { + func(*it); + } +} ExpEdge::ExpEdge(ExpEdge::fun_t typ, Expression*op) : ExpUnary(op), fun_(typ) @@ -527,6 +548,7 @@ ExpName::ExpName(ExpName*prefix, perm_string nn, Expression*msb, Expression*lsb) ExpName::~ExpName() { delete index_; + delete lsb_; } bool ExpName::symbolic_compare(const Expression*that) const diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index 479d207d5..803b63b49 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -32,7 +32,7 @@ class prange_t; class Entity; class ScopeBase; -class Subprogram; +class SubprogramHeader; class VType; class VTypeArray; class VTypePrimitive; @@ -460,17 +460,21 @@ class ExpConcat : public Expression { class ExpConditional : public Expression { public: - class else_t : public LineInfo { + class case_t : public LineInfo { public: - else_t(Expression*cond, std::list*tru); - else_t(const else_t&other); - ~else_t(); + case_t(Expression*cond, std::list*tru); + case_t(const case_t&other); + ~case_t(); + + inline Expression*condition() { return cond_; } + inline void set_condition(Expression*cond) { cond_ = cond; } int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*lt); - int emit_when_else(ostream&out, Entity*ent, ScopeBase*scope); - int emit_else(ostream&out, Entity*ent, ScopeBase*scope); + int emit_option(ostream&out, Entity*ent, ScopeBase*scope); + int emit_default(ostream&out, Entity*ent, ScopeBase*scope); void dump(ostream&out, int indent = 0) const; std::list& extract_true_clause() { return true_clause_; } + void visit(ExprVisitor& func); private: Expression*cond_; @@ -479,10 +483,10 @@ class ExpConditional : public Expression { public: ExpConditional(Expression*cond, std::list*tru, - std::list*fal); - ~ExpConditional(); + std::list*options); + virtual ~ExpConditional(); - Expression*clone() const; + virtual Expression*clone() const; const VType*probe_type(Entity*ent, ScopeBase*scope) const; int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); @@ -491,10 +495,22 @@ class ExpConditional : public Expression { void dump(ostream&out, int indent = 0) const; void visit(ExprVisitor& func); + protected: + std::list options_; +}; + +/* + * Expression to handle selected assignments (with .. select target <= value when ..) + */ +class ExpSelected : public ExpConditional { + public: + ExpSelected(Expression*selector, std::list*options); + ~ExpSelected(); + + Expression*clone() const; + private: - Expression*cond_; - std::list true_clause_; - std::list else_clause_; + Expression*selector_; }; /* @@ -548,7 +564,7 @@ class ExpFunc : public Expression { private: perm_string name_; std::vector argv_; - Subprogram*def_; + SubprogramHeader*def_; }; class ExpInteger : public Expression { @@ -662,6 +678,11 @@ class ExpName : public Expression { public: index_t(Expression*idx, Expression*size, Expression*offset = NULL) : idx_(idx), size_(size), offset_(offset) {} + ~index_t() { + delete idx_; + delete size_; + delete offset_; + } int emit(ostream&out, Entity*ent, ScopeBase*scope); diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 71cda7c97..c2d334af2 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -25,6 +25,7 @@ # include "vsignal.h" # include "subprogram.h" # include "library.h" +# include "std_types.h" # include # include # include "parse_types.h" @@ -714,22 +715,16 @@ int ExpConditional::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltyp /* Note that the type for the condition expression need not have anything to do with the type of this expression. */ - errors += cond_->elaborate_expr(ent, scope, 0); - for (list::const_iterator cur = true_clause_.begin() - ; cur != true_clause_.end() ; ++cur) { - errors += (*cur)->elaborate_expr(ent, scope, ltype); - } - - for (list::const_iterator cur = else_clause_.begin() - ; cur != else_clause_.end() ; ++cur) { + for (list::const_iterator cur = options_.begin() + ; cur != options_.end() ; ++cur) { errors += (*cur)->elaborate_expr(ent, scope, ltype); } return errors; } -int ExpConditional::else_t::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) +int ExpConditional::case_t::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) { int errors = 0; @@ -744,53 +739,22 @@ int ExpConditional::else_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); } - Subprogram*prog = scope->find_subprogram(name_); - - if(!prog) - prog = library_find_subprogram(name_); - - if(!prog) - return NULL; - return prog->peek_return_type(); } @@ -799,7 +763,7 @@ int ExpFunc::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) int errors = 0; ivl_assert(*this, scope); - Subprogram*prog = scope->find_subprogram(name_); + SubprogramHeader*prog = scope->find_subprogram(name_); if(!prog) prog = library_find_subprogram(name_); @@ -818,86 +782,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 - Subprogram*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 @@ -1037,6 +940,10 @@ const VType* ExpName::probe_type(Entity*ent, ScopeBase*scope) const return type; } + if (const InterfacePort*port = scope->find_param(name_)) { + return port->type; + } + if ((type = scope->is_enum_name(name_))) { return type; } @@ -1052,13 +959,22 @@ const VType* ExpName::fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*)co return probe_type(ent, scope); } -int ExpName::elaborate_expr(Entity*, ScopeBase*, const VType*ltype) +int ExpName::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) { if (ltype) { ivl_assert(*this, ltype != 0); set_type(ltype); } + if(prefix_.get()) + prefix_.get()->elaborate_expr(ent, scope, NULL); + + if(index_) + index_->elaborate_expr(ent, scope, &primitive_INTEGER); + + if(lsb_) + lsb_->elaborate_expr(ent, scope, &primitive_INTEGER); + return 0; } @@ -1069,7 +985,7 @@ const VType* ExpNameALL::probe_type(Entity*, ScopeBase*) const const VType* ExpRelation::probe_type(Entity*, ScopeBase*) const { - return &primitive_BOOLEAN; + return &type_BOOLEAN; } int ExpRelation::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index e7263e406..530e64d8d 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -23,7 +23,8 @@ # include "vtype.h" # include "architec.h" # include "package.h" -# include "subprogram.h" +# include "std_funcs.h" +# include "std_types.h" # include "parse_types.h" # include # include @@ -481,45 +482,33 @@ int ExpConditional::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; out << "("; - errors += cond_->emit(out, ent, scope); - out << ")? ("; - - if (true_clause_.size() > 1) { - cerr << get_fileline() << ": sorry: Multiple expression waveforms not supported here." << endl; - errors += 1; - } - - Expression*tmp = true_clause_.front(); - errors += tmp->emit(out, ent, scope); - - out << ") : ("; // Draw out any when-else expressions. These are all the else_ // clauses besides the last. - if (else_clause_.size() > 1) { - list::iterator last = else_clause_.end(); - -- last; + if (options_.size() > 1) { + list::iterator last = options_.end(); + --last; - for (list::iterator cur = else_clause_.begin() + for (list::iterator cur = options_.begin() ; cur != last ; ++cur) { - errors += (*cur) ->emit_when_else(out, ent, scope); + errors += (*cur)->emit_option(out, ent, scope); } - } + } - errors += else_clause_.back()->emit_else(out, ent, scope); + errors += options_.back()->emit_default(out, ent, scope); out << ")"; - // The emit_when_else() functions do not close the last + // The emit_option() functions do not close the last // parentheses so that the following expression can be // nested. But that means come the end, we have some // expressions to close. - for (size_t idx = 1 ; idx < else_clause_.size() ; idx += 1) + for (size_t idx = 1 ; idx < options_.size() ; idx += 1) out << ")"; return errors; } -int ExpConditional::else_t::emit_when_else(ostream&out, Entity*ent, ScopeBase*scope) +int ExpConditional::case_t::emit_option(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; assert(cond_ != 0); @@ -541,7 +530,7 @@ int ExpConditional::else_t::emit_when_else(ostream&out, Entity*ent, ScopeBase*sc return errors; } -int ExpConditional::else_t::emit_else(ostream&out, Entity*ent, ScopeBase*scope) +int ExpConditional::case_t::emit_default(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; // Trailing else must have no condition. @@ -579,103 +568,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; } @@ -767,6 +674,11 @@ int ExpName::emit(ostream&out, Entity*ent, ScopeBase*scope) if(try_workarounds_(out, ent, scope, indices, field_size)) { emit_workaround_(out, ent, scope, indices, field_size); + for(list::iterator it = indices.begin(); + it != indices.end(); ++it) + { + delete *it; + } return 0; } @@ -847,7 +759,7 @@ bool ExpName::check_const_array_workaround_(const VTypeArray*arr, data_size = element->get_width(scope); if(data_size < 0) return false; - indices.push_back(new index_t(index_, new ExpInteger(data_size))); + indices.push_back(new index_t(index_->clone(), new ExpInteger(data_size))); return true; } @@ -1044,7 +956,14 @@ int ExpUAbs::emit(ostream&out, Entity*ent, ScopeBase*scope) int ExpUNot::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; - out << "~("; + + const VType*op_type = peek_operand()->probe_type(ent, scope); + + if(op_type && op_type->type_match(&type_BOOLEAN)) + out << "!("; + else + out << "~("; + errors += emit_operand1(out, ent, scope); out << ")"; return errors; diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index b0594c38d..c6d9d0b31 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -22,6 +22,7 @@ # include "parse_misc.h" # include "compiler.h" # include "package.h" +# include "std_types.h" # include # include # include @@ -72,9 +73,9 @@ void library_add_directory(const char*directory) library_search_path.push_front(directory); } -Subprogram*library_find_subprogram(perm_string name) +SubprogramHeader*library_find_subprogram(perm_string name) { - Subprogram*subp = NULL; + SubprogramHeader*subp = NULL; map::const_iterator lib_it; for(lib_it = libraries.begin(); lib_it != libraries.end(); ++lib_it) { @@ -305,9 +306,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); } } @@ -320,14 +319,10 @@ static void import_ieee_use_numeric_bit(ActiveScope*res, perm_string name) bool all_flag = name=="all"; if (all_flag || name == "signed") { - vector dims (1); - res->use_name(perm_string::literal("signed"), - new VTypeArray(&primitive_STDLOGIC, dims, true)); + res->use_name(perm_string::literal("signed"), &primitive_SIGNED); } if (all_flag || name == "unsigned") { - vector dims (1); - res->use_name(perm_string::literal("unsigned"), - new VTypeArray(&primitive_BIT, dims, false)); + res->use_name(perm_string::literal("unsigned"), &primitive_UNSIGNED); } } @@ -336,14 +331,10 @@ static void import_ieee_use_numeric_std(ActiveScope*res, perm_string name) bool all_flag = name=="all"; if (all_flag || name == "signed") { - vector dims (1); - res->use_name(perm_string::literal("signed"), - new VTypeArray(&primitive_STDLOGIC, dims, true)); + res->use_name(perm_string::literal("signed"), &primitive_SIGNED); } if (all_flag || name == "unsigned") { - vector dims (1); - res->use_name(perm_string::literal("unsigned"), - new VTypeArray(&primitive_STDLOGIC, dims, false)); + res->use_name(perm_string::literal("unsigned"), &primitive_UNSIGNED); } } @@ -384,59 +375,6 @@ static void import_std_use(const YYLTYPE&loc, ActiveScope*/*res*/, perm_string p } } -const VTypePrimitive primitive_BOOLEAN(VTypePrimitive::BOOLEAN, true); -const VTypePrimitive primitive_BIT(VTypePrimitive::BIT, true); -const VTypePrimitive primitive_INTEGER(VTypePrimitive::INTEGER); -const VTypePrimitive primitive_NATURAL(VTypePrimitive::NATURAL); -const VTypePrimitive primitive_REAL(VTypePrimitive::REAL); -const VTypePrimitive primitive_STDLOGIC(VTypePrimitive::STDLOGIC, true); -const VTypePrimitive primitive_CHARACTER(VTypePrimitive::CHARACTER); -const VTypePrimitive primitive_TIME(VTypePrimitive::TIME); - -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)); - -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); -} - -void emit_std_types(ostream&out) -{ - out << "`ifndef __VHDL_STD_TYPES" << endl; - out << "`define __VHDL_STD_TYPES" << endl; - out << "typedef enum bit { \\false , \\true } boolean ;" << endl; - out << "`endif" << endl; -} - -bool is_global_type(perm_string name) -{ - if (name == "boolean") return true; - if (name == "bit") 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; - if (name == "unsigned") return true; - if (name == "time") return true; - return false; -} - void library_set_work_path(const char*path) { assert(library_work_path == 0); diff --git a/vhdlpp/library.h b/vhdlpp/library.h index fe04aad23..68009a39a 100644 --- a/vhdlpp/library.h +++ b/vhdlpp/library.h @@ -19,15 +19,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -class Subprogram; +class SubprogramHeader; extern void library_set_work_path(const char*work_path); extern void library_add_directory(const char*directory); -extern Subprogram*library_find_subprogram(perm_string name); - -extern void emit_std_types(ostream&out); -extern int emit_packages(void); +extern SubprogramHeader*library_find_subprogram(perm_string name); #endif /* IVL_library_H */ diff --git a/vhdlpp/main.cc b/vhdlpp/main.cc index 418e73daa..10d901250 100644 --- a/vhdlpp/main.cc +++ b/vhdlpp/main.cc @@ -76,6 +76,8 @@ const char NOTICE[] = # include "compiler.h" # include "library.h" +# include "std_funcs.h" +# include "std_types.h" # include "parse_api.h" # include "vtype.h" # include @@ -184,6 +186,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/package.cc b/vhdlpp/package.cc index 167c8a279..64d20fc80 100644 --- a/vhdlpp/package.cc +++ b/vhdlpp/package.cc @@ -22,6 +22,7 @@ # include "entity.h" # include "subprogram.h" # include "parse_misc.h" +# include "std_types.h" # include "ivl_assert.h" Package::Package(perm_string n, const ActiveScope&ref) @@ -57,6 +58,11 @@ void Package::write_to_stream(ostream&fd) const const VTypeDef*def = dynamic_cast (cur->second); if (def == 0) continue; + + // Do not include global types in types dump + if (is_global_type(cur->first)) + continue; + fd << "type " << cur->first << ";" << endl; } for (map::const_iterator cur = cur_types_.begin() @@ -64,6 +70,11 @@ void Package::write_to_stream(ostream&fd) const const VTypeDef*def = dynamic_cast (cur->second); if (def == 0) continue; + + // Do not include global types in types dump + if (is_global_type(cur->first)) + continue; + fd << "type " << cur->first << ";" << endl; } @@ -111,9 +122,10 @@ void Package::write_to_stream(ostream&fd) const fd << ";" << endl; } - for (map::const_iterator cur = cur_subprograms_.begin() + for (map::const_iterator cur = cur_subprograms_.begin() ; cur != cur_subprograms_.end() ; ++cur) { cur->second->write_to_stream(fd); + fd << ";" << endl; } for (map::const_iterator cur = old_components_.begin() @@ -130,9 +142,14 @@ void Package::write_to_stream(ostream&fd) const fd << "end package " << name_ << ";" << endl; fd << "package body " << name_ << " is" << endl; - for (map::const_iterator cur = cur_subprograms_.begin() + for (map::const_iterator cur = cur_subprograms_.begin() ; cur != cur_subprograms_.end() ; ++cur) { - cur->second->write_to_stream_body(fd); + SubprogramHeader*subp = cur->second; + if(subp->body()) { + subp->write_to_stream(fd); + fd << " is" << endl; + subp->body()->write_to_stream(fd); + } } fd << "end " << name_ << ";" << endl; } diff --git a/vhdlpp/package.h b/vhdlpp/package.h index a8e303cd5..fb6bfb8ac 100644 --- a/vhdlpp/package.h +++ b/vhdlpp/package.h @@ -36,7 +36,7 @@ class Package : public Scope, public LineInfo { perm_string name() const { return name_; } - Subprogram* recall_subprogram(perm_string name) const; + SubprogramHeader* 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 d8db4494d..77d314231 100644 --- a/vhdlpp/package_emit.cc +++ b/vhdlpp/package_emit.cc @@ -64,7 +64,7 @@ int Package::emit_package(ostream&fd) const //} fd << "package \\" << name() << " ;" << endl; - for (map::const_iterator cur = cur_subprograms_.begin() + for (map::const_iterator cur = cur_subprograms_.begin() ; cur != cur_subprograms_.end() ; ++ cur) { // Do not emit unbounded functions, we will just need fixed instances later if(!cur->second->unbounded()) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 8188052ba..6a7fb2295 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -39,6 +39,8 @@ # include "package.h" # include "vsignal.h" # include "vtype.h" +# include "std_funcs.h" +# include "std_types.h" # include # include # include @@ -83,7 +85,7 @@ extern int yylex(union YYSTYPE*yylvalp,YYLTYPE*yyllocp,yyscan_t yyscanner); */ static ActiveScope*active_scope = new ActiveScope; static stack scope_stack; -static Subprogram*active_sub = NULL; +static SubprogramHeader*active_sub = NULL; // perm_strings for attributes const static perm_string left_attr = perm_string::literal("left"); @@ -146,6 +148,7 @@ void parser_cleanup(void) { delete_design_entities(); delete_global_scope(); + delete_std_funcs(); lex_strings.cleanup(); } @@ -228,8 +231,8 @@ static void touchup_interface_for_functions(std::list*ports) IfSequential::Elsif*elsif; std::list*elsif_list; - ExpConditional::else_t*exp_else; - std::list*exp_else_list; + ExpConditional::case_t*exp_options; + std::list*exp_options_list; CaseSeqStmt::CaseStmtAlternative* case_alt; std::list* case_alt_list; @@ -262,7 +265,7 @@ static void touchup_interface_for_functions(std::list*ports) ReportStmt::severity_t severity; - Subprogram*subprogram; + SubprogramHeader*subprogram; }; /* The keywords are all tokens. */ @@ -308,6 +311,7 @@ static void touchup_interface_for_functions(std::list*ports) %type interface_element interface_list %type port_clause port_clause_opt %type generic_clause generic_clause_opt +%type parameter_list parameter_list_opt %type mode mode_opt %type entity_aspect entity_aspect_opt binding_indication binding_indication_semicolon_opt @@ -318,7 +322,7 @@ static void touchup_interface_for_functions(std::list*ports) %type concurrent_conditional_signal_assignment %type concurrent_signal_assignment_statement concurrent_simple_signal_assignment %type for_generate_statement generate_statement if_generate_statement -%type process_statement +%type process_statement selected_signal_assignment %type architecture_statement_part generate_statement_body %type choice @@ -331,8 +335,8 @@ 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 simple_expression_2 term waveform_element -%type interface_element_expression +%type simple_expression simple_expression_2 term +%type variable_declaration_assign_opt waveform_element interface_element_expression %type waveform waveform_elements %type name_list expression_list @@ -370,10 +374,12 @@ static void touchup_interface_for_functions(std::list*ports) %type if_statement_elsif %type if_statement_elsif_list if_statement_elsif_list_opt -%type else_when_waveform -%type else_when_waveforms +%type else_when_waveform selected_waveform +%type else_when_waveforms selected_waveform_list + +%type function_specification procedure_specification +%type subprogram_specification subprogram_body_start -%type function_specification subprogram_specification subprogram_body_start %type severity severity_opt %% @@ -800,12 +806,12 @@ concurrent_simple_signal_assignment else_when_waveforms : else_when_waveforms else_when_waveform - { list*tmp = $1; + { list*tmp = $1; tmp ->push_back($2); $$ = tmp; } | else_when_waveform - { list*tmp = new list; + { list*tmp = new list; tmp->push_back($1); $$ = tmp; } @@ -813,12 +819,12 @@ else_when_waveforms else_when_waveform : K_else waveform K_when expression - { ExpConditional::else_t*tmp = new ExpConditional::else_t($4, $2); + { ExpConditional::case_t*tmp = new ExpConditional::case_t($4, $2); FILE_NAME(tmp, @1); $$ = tmp; } | K_else waveform - { ExpConditional::else_t*tmp = new ExpConditional::else_t(0, $2); + { ExpConditional::case_t*tmp = new ExpConditional::case_t(0, $2); FILE_NAME(tmp, @1); $$ = tmp; } @@ -827,11 +833,21 @@ else_when_waveform concurrent_signal_assignment_statement /* IEEE 1076-2008 P11.6 */ : concurrent_simple_signal_assignment - | IDENTIFIER ':' concurrent_simple_signal_assignment { $$ = $3; } + | IDENTIFIER ':' concurrent_simple_signal_assignment + { delete[] $1; + $$ = $3; + } | concurrent_conditional_signal_assignment - | IDENTIFIER ':' concurrent_conditional_signal_assignment { $$ = $3; } + | IDENTIFIER ':' concurrent_conditional_signal_assignment + { delete[] $1; + $$ = $3; + } + + | selected_signal_assignment + + | IDENTIFIER ':' selected_signal_assignment { $$ = $3; } | name LEQ error ';' { errormsg(@2, "Syntax error in signal assignment waveform.\n"); @@ -968,6 +984,7 @@ direction : K_to { $$ = false; } | K_downto { $$ = true; } ; element_association : choices ARROW expression { ExpAggregate::element_t*tmp = new ExpAggregate::element_t($1, $3); + delete $1; $$ = tmp; } | expression @@ -991,7 +1008,9 @@ element_association_list element_declaration : identifier_list ':' subtype_indication ';' - { $$ = record_elements($1, $3); } + { $$ = record_elements($1, $3); + delete $1; + } ; element_declaration_list @@ -1237,15 +1256,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); + : K_function IDENTIFIER parameter_list K_return IDENTIFIER + { perm_string type_name = lex_strings.make($5); 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); + touchup_interface_for_functions($3); + SubprogramHeader*tmp = new SubprogramHeader(name, $3, type_mark); + FILE_NAME(tmp, @1); delete[]$2; - delete[]$7; + delete[]$5; $$ = tmp; } ; @@ -1267,8 +1286,8 @@ generic_clause_opt ; generic_clause - : K_generic '(' interface_list ')' ';' - { $$ = $3; } + : K_generic parameter_list ';' + { $$ = $2; } | K_generic '(' error ')' ';' { errormsg(@3, "Error in interface list for generic.\n"); yyerrok; @@ -1306,7 +1325,7 @@ identifier_list } ; -identifier_opt : IDENTIFIER { $$ = $1; } | { $$ = 0; } ; +identifier_opt : IDENTIFIER { $$ = $1; } | { $$ = 0; } ; identifier_colon_opt : IDENTIFIER ':' { $$ = $1; } | { $$ = 0; }; @@ -1591,14 +1610,7 @@ mode_opt : mode {$$ = $1;} | {$$ = PORT_NONE;} ; name /* IEEE 1076-2008 P8.1 */ : IDENTIFIER /* simple_name (IEEE 1076-2008 P8.2) */ - { Expression*tmp; - if(!strcasecmp($1, "true")) - tmp = new ExpBitstring("1"); - else if(!strcasecmp($1, "false")) - tmp = new ExpBitstring("0"); - else - tmp = new ExpName(lex_strings.make($1)); - + { Expression*tmp = new ExpName(lex_strings.make($1)); FILE_NAME(tmp, @1); delete[]$1; $$ = tmp; @@ -1764,9 +1776,18 @@ package_body_start } ; +parameter_list + : '(' interface_list ')' { $$ = $2; } + ; + +parameter_list_opt + : parameter_list { $$ = $1; } + | { $$ = 0; } + ; + port_clause - : K_port '(' interface_list ')' ';' - { $$ = $3; } + : K_port parameter_list ';' + { $$ = $2; } | K_port '(' error ')' ';' { errormsg(@1, "Syntax error in port list.\n"); yyerrok; @@ -1872,6 +1893,7 @@ primary VHDL syntax). */ | IDENTIFIER '(' association_list ')' { sorrymsg(@1, "Function calls not supported\n"); + delete[] $1; $$ = 0; } @@ -1890,19 +1912,26 @@ primary_unit ; procedure_call - : IDENTIFIER + : IDENTIFIER ';' { ProcedureCall* tmp = new ProcedureCall(lex_strings.make($1)); - sorrymsg(@1, "Procedure calls are not supported.\n"); + delete[] $1; $$ = tmp; } - | IDENTIFIER '(' association_list ')' + | IDENTIFIER '(' association_list ')' ';' { ProcedureCall* tmp = new ProcedureCall(lex_strings.make($1), $3); - sorrymsg(@1, "Procedure calls are not supported.\n"); + delete[] $1; $$ = tmp; } - | IDENTIFIER '(' error ')' + | IDENTIFIER '(' expression_list ')' ';' + { + ProcedureCall* tmp = new ProcedureCall(lex_strings.make($1), $3); + delete[] $1; + delete $3; // parameters are copied in this variant + $$ = tmp; + } + | IDENTIFIER '(' error ')' ';' { errormsg(@1, "Errors in procedure call.\n"); yyerrok; delete[]$1; @@ -1911,10 +1940,24 @@ procedure_call ; procedure_call_statement - : IDENTIFIER ':' procedure_call { $$ = $3; } + : IDENTIFIER ':' procedure_call + { delete[] $1; + $$ = $3; + } | procedure_call { $$ = $1; } ; +procedure_specification /* IEEE 1076-2008 P4.2.1 */ + : K_procedure IDENTIFIER parameter_list_opt + { perm_string name = lex_strings.make($2); + touchup_interface_for_functions($3); + SubprogramHeader*tmp = new SubprogramHeader(name, $3, NULL); + FILE_NAME(tmp, @1); + delete[]$2; + $$ = tmp; + } + ; + process_declarative_item : variable_declaration ; @@ -2175,6 +2218,47 @@ selected_names_lib | selected_name_lib ; +selected_signal_assignment + : K_with expression K_select name LEQ selected_waveform_list ';' + { ExpSelected*tmp = new ExpSelected($2, $6); + FILE_NAME(tmp, @3); + delete $2; + delete $6; + + ExpName*name = dynamic_cast($4); + assert(name); + SignalAssignment*tmpa = new SignalAssignment(name, tmp); + FILE_NAME(tmpa, @1); + + $$ = tmpa; + } + ; + +selected_waveform + : waveform K_when expression + { ExpConditional::case_t*tmp = new ExpConditional::case_t($3, $1); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | waveform K_when K_others + { ExpConditional::case_t*tmp = new ExpConditional::case_t(0, $1); + FILE_NAME(tmp, @1); + $$ = tmp; + } + ; + +selected_waveform_list + : selected_waveform_list ',' selected_waveform + { list*tmp = $1; + tmp->push_back($3); + $$ = tmp; + } + | selected_waveform + { list*tmp = new list; + tmp->push_back($1); + $$ = tmp; + } + ; sequence_of_statements : sequence_of_statements sequential_statement @@ -2224,6 +2308,7 @@ severity errormsg(@1, "Invalid severity level (possible values: NOTE, WARNING, ERROR, FAILURE).\n"); $$ = ReportStmt::UNSPECIFIED; } + delete[] $2; } severity_opt @@ -2359,7 +2444,10 @@ signal_assignment signal_assignment_statement : signal_assignment - | IDENTIFIER ':' signal_assignment { $$ = $3; } + | IDENTIFIER ':' signal_assignment + { delete[] $1; + $$ = $3; + } subprogram_body_start : subprogram_specification K_is @@ -2375,16 +2463,20 @@ subprogram_body /* IEEE 1076-2008 P4.3 */ : subprogram_body_start subprogram_declarative_part K_begin subprogram_statement_part K_end subprogram_kind_opt identifier_opt ';' - { Subprogram*prog = $1; - Subprogram*tmp = active_scope->recall_subprogram(prog->name()); + { SubprogramHeader*prog = $1; + SubprogramHeader*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->transfer_from(*active_scope, ScopeBase::VARIABLES); - prog->set_program_body($4); + + SubprogramBody*body = new SubprogramBody(); + body->transfer_from(*active_scope, ScopeBase::VARIABLES); + body->set_statements($4); + + prog->set_body(body); active_scope->bind_name(prog->name(), prog); active_sub = NULL; } @@ -2429,6 +2521,7 @@ subprogram_kind_opt : subprogram_kind | ; subprogram_specification : function_specification { $$ = $1; } + | procedure_specification { $$ = $1; } ; /* This is an implementation of the rule: @@ -2444,6 +2537,7 @@ subprogram_statement_part subtype_declaration : K_subtype IDENTIFIER K_is subtype_indication ';' { perm_string name = lex_strings.make($2); + delete[] $2; if ($4 == 0) { errormsg(@1, "Failed to declare type name %s.\n", name.str()); } else { @@ -2593,7 +2687,10 @@ use_clauses_opt variable_assignment_statement /* IEEE 1076-2008 P10.6.1 */ : variable_assignment - | IDENTIFIER ':' variable_assignment { $$ = $3; } + | IDENTIFIER ':' variable_assignment + { delete[] $1; + $$ = $3; + } variable_assignment : name VASSIGN expression ';' @@ -2616,11 +2713,12 @@ variable_assignment ; variable_declaration /* IEEE 1076-2008 P6.4.2.4 */ - : K_shared_opt K_variable identifier_list ':' subtype_indication ';' + : K_shared_opt K_variable identifier_list ':' subtype_indication + variable_declaration_assign_opt ';' { /* Save the signal declaration in the block_signals map. */ for (std::list::iterator cur = $3->begin() ; cur != $3->end() ; ++cur) { - Variable*sig = new Variable(*cur, $5); + Variable*sig = new Variable(*cur, $5, $6); FILE_NAME(sig, @2); active_scope->bind_name(*cur, sig); } @@ -2632,6 +2730,11 @@ variable_declaration /* IEEE 1076-2008 P6.4.2.4 */ } ; +variable_declaration_assign_opt + : VASSIGN expression { $$ = $2; } + | { $$ = 0; } + ; + wait_statement : K_wait K_for expression ';' { WaitForStmt*tmp = new WaitForStmt($3); diff --git a/vhdlpp/parse_misc.h b/vhdlpp/parse_misc.h index e4aa9e644..a18335245 100644 --- a/vhdlpp/parse_misc.h +++ b/vhdlpp/parse_misc.h @@ -63,8 +63,4 @@ 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); -extern void generate_global_types(ActiveScope*res); - -extern bool is_global_type(perm_string type_name); - #endif /* IVL_parse_misc_H */ diff --git a/vhdlpp/scope.cc b/vhdlpp/scope.cc index 49b422e89..d0a329514 100644 --- a/vhdlpp/scope.cc +++ b/vhdlpp/scope.cc @@ -22,6 +22,8 @@ # include "package.h" # include "subprogram.h" # include "entity.h" +# include "std_funcs.h" +# include "std_types.h" # include # include # include @@ -65,9 +67,9 @@ ScopeBase::ScopeBase(const ActiveScope&ref) // 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); + for (map::iterator cur = cur_subprograms_.begin() + ; cur != cur_subprograms_.end(); ++cur) { + cur->second->set_parent(this); } } @@ -156,15 +158,20 @@ Variable* ScopeBase::find_variable(perm_string by_name) const } } -const InterfacePort* ScopeBase::find_param(perm_string by_name) const +const InterfacePort* ScopeBase::find_param(perm_string) const { - for(map::const_iterator it = use_subprograms_.begin(); + return NULL; +} + +const InterfacePort* ScopeBase::find_param_all(perm_string by_name) const +{ + for(map::const_iterator it = use_subprograms_.begin(); it != use_subprograms_.end(); ++it) { if(const InterfacePort*port = it->second->find_param(by_name)) return port; } - for(map::const_iterator it = cur_subprograms_.begin(); + for(map::const_iterator it = cur_subprograms_.begin(); it != cur_subprograms_.end(); ++it) { if(const InterfacePort*port = it->second->find_param(by_name)) return port; @@ -173,9 +180,9 @@ const InterfacePort* ScopeBase::find_param(perm_string by_name) const return NULL; } -Subprogram* ScopeBase::find_subprogram(perm_string name) const +SubprogramHeader* ScopeBase::find_subprogram(perm_string name) const { - map::const_iterator cur; + map::const_iterator cur; cur = cur_subprograms_.find(name); if (cur != cur_subprograms_.end()) @@ -185,7 +192,7 @@ Subprogram* 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 @@ -196,7 +203,7 @@ const VTypeEnum* ScopeBase::is_enum_name(perm_string name) const return *it; } - return NULL; + return find_std_enum_name(name); } /* @@ -218,7 +225,7 @@ void ScopeBase::do_use_from(const ScopeBase*that) old_components_[cur->first] = cur->second; } - for (map::const_iterator cur = that->cur_subprograms_.begin() + for (map::const_iterator cur = that->cur_subprograms_.begin() ; cur != that->cur_subprograms_.end() ; ++ cur) { if (cur->second == 0) continue; @@ -274,9 +281,9 @@ void ActiveScope::set_package_header(Package*pkg) package_header_ = pkg; } -Subprogram* ActiveScope::recall_subprogram(perm_string name) const +SubprogramHeader* ActiveScope::recall_subprogram(perm_string name) const { - if (Subprogram*tmp = find_subprogram(name)) + if (SubprogramHeader*tmp = find_subprogram(name)) return tmp; if (package_header_) diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index 709e552ec..1f9ba26be 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -32,7 +32,7 @@ class ActiveScope; class Architecture; class ComponentBase; class Package; -class Subprogram; +class SubprogramHeader; class VType; template @@ -57,7 +57,8 @@ class ScopeBase { Signal* find_signal(perm_string by_name) const; Variable* find_variable(perm_string by_name) const; virtual const InterfacePort* find_param(perm_string by_name) const; - Subprogram* find_subprogram(perm_string by_name) const; + const InterfacePort* find_param_all(perm_string by_name) const; + SubprogramHeader* find_subprogram(perm_string by_name) const; // Checks if a string is one of possible enum values. If so, the enum // type is returned, otherwise NULL. const VTypeEnum* is_enum_name(perm_string name) const; @@ -67,8 +68,8 @@ class ScopeBase { enum transfer_type_t { SIGNALS = 1, VARIABLES = 2, COMPONENTS = 4, ALL = 0xffff }; void transfer_from(ScopeBase&ref, transfer_type_t what = ALL); - inline void bind_subprogram(perm_string name, Subprogram*obj) - { map::iterator it; + inline void bind_subprogram(perm_string name, SubprogramHeader*obj) + { map::iterator it; if((it = use_subprograms_.find(name)) != use_subprograms_.end() ) use_subprograms_.erase(it); cur_subprograms_[name] = obj; @@ -116,8 +117,8 @@ class ScopeBase { std::map use_constants_; //imported constants std::map cur_constants_; //current constants - std::map use_subprograms_; //imported - std::map cur_subprograms_; //current + std::map use_subprograms_; //imported + std::map cur_subprograms_; //current std::list use_enums_; @@ -170,7 +171,7 @@ class ActiveScope : public ScopeBase { // 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; + SubprogramHeader* 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 @@ -219,8 +220,8 @@ class ActiveScope : public ScopeBase { cur_constants_[name] = new const_t(obj, val); } - inline void bind_name(perm_string name, Subprogram*obj) - { map::iterator it; + inline void bind_name(perm_string name, SubprogramHeader*obj) + { map::iterator it; if((it = use_subprograms_.find(name)) != use_subprograms_.end() ) use_subprograms_.erase(it); cur_subprograms_[name] = obj; diff --git a/vhdlpp/sequential.cc b/vhdlpp/sequential.cc index 0f793b713..a0f2878cb 100644 --- a/vhdlpp/sequential.cc +++ b/vhdlpp/sequential.cc @@ -169,17 +169,31 @@ void CaseSeqStmt::CaseStmtAlternative::visit(SeqStmtVisitor& func) } ProcedureCall::ProcedureCall(perm_string name) -: name_(name), param_list_(0) +: name_(name), param_list_(NULL), def_(NULL) { } ProcedureCall::ProcedureCall(perm_string name, std::list* param_list) -: name_(name), param_list_(param_list) +: name_(name), param_list_(param_list), def_(NULL) { } +ProcedureCall::ProcedureCall(perm_string name, std::list* param_list) +: name_(name), def_(NULL) +{ + param_list_ = new std::list; + for(std::list::const_iterator it = param_list->begin(); + it != param_list->end(); ++it) + { + param_list_->push_back(new named_expr_t(empty_perm_string, (*it)->clone())); + } +} + ProcedureCall::~ProcedureCall() { + if(!param_list_) + return; + while(param_list_->size() > 0) { named_expr_t* cur = param_list_->front(); param_list_->pop_front(); diff --git a/vhdlpp/sequential.h b/vhdlpp/sequential.h index eba398cef..12a57f6a1 100644 --- a/vhdlpp/sequential.h +++ b/vhdlpp/sequential.h @@ -203,6 +203,7 @@ class ProcedureCall : public SequentialStmt { public: ProcedureCall(perm_string name); ProcedureCall(perm_string name, std::list* param_list); + ProcedureCall(perm_string name, std::list* param_list); ~ProcedureCall(); int elaborate(Entity*ent, ScopeBase*scope); @@ -212,6 +213,7 @@ class ProcedureCall : public SequentialStmt { private: perm_string name_; std::list* param_list_; + SubprogramHeader*def_; }; class VariableSeqAssignment : public SequentialStmt { diff --git a/vhdlpp/sequential_elaborate.cc b/vhdlpp/sequential_elaborate.cc index 80e7b2584..4f3af82b0 100644 --- a/vhdlpp/sequential_elaborate.cc +++ b/vhdlpp/sequential_elaborate.cc @@ -20,6 +20,8 @@ # include "sequential.h" # include "expression.h" # include "scope.h" +# include "library.h" +# include "subprogram.h" int SequentialStmt::elaborate(Entity*, ScopeBase*) { @@ -149,16 +151,39 @@ 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); } return errors; } -int ProcedureCall::elaborate(Entity*, ScopeBase*) +int ProcedureCall::elaborate(Entity*ent, ScopeBase*scope) { - return 0; + int errors = 0; + + def_ = scope->find_subprogram(name_); + + if(!def_) + def_ = library_find_subprogram(name_); + + assert(def_); + + // Elaborate arguments + size_t idx = 0; + if(param_list_) { + for(list::iterator cur = param_list_->begin() + ; cur != param_list_->end() ; ++cur) { + const VType*tmp = (*cur)->expr()->probe_type(ent, scope); + const VType*param_type = def_ ? def_->peek_param_type(idx) : NULL; + + if(!tmp && param_type) + tmp = param_type; + + errors += (*cur)->expr()->elaborate_expr(ent, scope, tmp); + } + } + + return errors; } int VariableSeqAssignment::elaborate(Entity*ent, ScopeBase*scope) diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index 619c0f5e5..7148e2b52 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -23,7 +23,9 @@ # include "sequential.h" # include "expression.h" # include "architec.h" +# include "package.h" # include "compiler.h" +# include "subprogram.h" # include # include # include @@ -205,12 +207,29 @@ void VariableSeqAssignment::write_to_stream(ostream&fd) fd << ";" << endl; } -int ProcedureCall::emit(ostream&out, Entity*, ScopeBase*) +int ProcedureCall::emit(ostream&out, Entity*ent, ScopeBase*scope) { - out << " // " << get_fileline() << ": internal error: " - << "I don't know how to emit this sequential statement! " - << "type=" << typeid(*this).name() << endl; - return 1; + int errors = 0; + + std::vectorparams(param_list_->size()); + int i = 0; + for(std::list::iterator it = param_list_->begin(); + it != param_list_->end(); ++it) + params[i++] = (*it)->expr(); + + const Package*pkg = dynamic_cast (def_->get_parent()); + if (pkg != 0) + out << "\\" << pkg->name() << " ::"; + + errors += def_->emit_name(params, out, ent, scope); + + out << " ("; + if(param_list_) { + errors += def_->emit_args(params, out, ent, scope); + } + + out << ");" << endl; + return errors; } int LoopStatement::emit_substatements(ostream&out, Entity*ent, ScopeBase*scope) diff --git a/vhdlpp/std_funcs.cc b/vhdlpp/std_funcs.cc new file mode 100644 index 000000000..ec843dd13 --- /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 "std_types.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, &type_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, &type_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/std_types.cc b/vhdlpp/std_types.cc new file mode 100644 index 000000000..20acb42a6 --- /dev/null +++ b/vhdlpp/std_types.cc @@ -0,0 +1,119 @@ +/* + * 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_types.h" +#include "scope.h" + +static std::map std_types; +// this list contains enums used by typedefs in the std_types map +static std::list std_enums; + +const VTypePrimitive primitive_BIT(VTypePrimitive::BIT, true); +const VTypePrimitive primitive_INTEGER(VTypePrimitive::INTEGER); +const VTypePrimitive primitive_NATURAL(VTypePrimitive::NATURAL); +const VTypePrimitive primitive_REAL(VTypePrimitive::REAL); +const VTypePrimitive primitive_STDLOGIC(VTypePrimitive::STDLOGIC, true); +const VTypePrimitive primitive_CHARACTER(VTypePrimitive::CHARACTER); +const VTypePrimitive primitive_TIME(VTypePrimitive::TIME); + +VTypeDef type_BOOLEAN(perm_string::literal("boolean")); + +const VTypeArray primitive_BIT_VECTOR(&primitive_BIT, vector (1)); +const VTypeArray primitive_BOOL_VECTOR(&type_BOOLEAN, vector (1)); +const VTypeArray primitive_STDLOGIC_VECTOR(&primitive_STDLOGIC, vector (1)); +const VTypeArray primitive_STRING(&primitive_CHARACTER, vector (1)); +const VTypeArray primitive_SIGNED(&primitive_STDLOGIC, vector (1), true); +const VTypeArray primitive_UNSIGNED(&primitive_STDLOGIC, vector (1), false); + +void generate_global_types(ActiveScope*res) +{ + // boolean + std::list*enum_BOOLEAN_vals = new std::list; + enum_BOOLEAN_vals->push_back(perm_string::literal("false")); + enum_BOOLEAN_vals->push_back(perm_string::literal("true")); + VTypeEnum*enum_BOOLEAN = new VTypeEnum(enum_BOOLEAN_vals); + type_BOOLEAN.set_definition(enum_BOOLEAN); + std_types[type_BOOLEAN.peek_name()] = &type_BOOLEAN; + std_enums.push_back(enum_BOOLEAN); + + res->use_name(type_BOOLEAN.peek_name(), &type_BOOLEAN); + res->use_name(perm_string::literal("bit"), &primitive_BIT); + res->use_name(perm_string::literal("bit_vector"), &primitive_BIT_VECTOR); + 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 delete_global_types() +{ + typedef_context_t typedef_ctx; + for(map::iterator cur = std_types.begin(); + cur != std_types.end() ; ++ cur) { + delete cur->second->peek_definition(); + delete cur->second; + } +} + +const VTypeEnum*find_std_enum_name(perm_string name) +{ + for(list::const_iterator it = std_enums.begin(); + it != std_enums.end(); ++it) { + if((*it)->has_name(name)) + return *it; + } + + return NULL; +} + +void emit_std_types(ostream&fd) +{ + fd << "`ifndef __VHDL_STD_TYPES" << endl; + fd << "`define __VHDL_STD_TYPES" << endl; + typedef_context_t typedef_ctx; + for(map::iterator cur = std_types.begin(); + cur != std_types.end() ; ++ cur) { + cur->second->emit_typedef(fd, typedef_ctx); + } + fd << "`endif" << endl; +} + +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 == "string") return true; + if (name == "natural") return true; + if (name == "signed") return true; + if (name == "unsigned") return true; + if (name == "time") return true; + + return std_types.count(name) > 0; +} + diff --git a/vhdlpp/std_types.h b/vhdlpp/std_types.h new file mode 100644 index 000000000..b38003cf4 --- /dev/null +++ b/vhdlpp/std_types.h @@ -0,0 +1,48 @@ +/* + * 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 "vtype.h" + +class ActiveScope; + +void emit_std_types(ostream&out); +int emit_packages(void); +void generate_global_types(ActiveScope*res); +bool is_global_type(perm_string type_name); +void delete_global_types(); +const VTypeEnum*find_std_enum_name(perm_string name); + +extern const VTypePrimitive primitive_BOOLEAN; +extern const VTypePrimitive primitive_BIT; +extern const VTypePrimitive primitive_INTEGER; +extern const VTypePrimitive primitive_NATURAL; +extern const VTypePrimitive primitive_REAL; +extern const VTypePrimitive primitive_STDLOGIC; +extern const VTypePrimitive primitive_CHARACTER; +extern const VTypePrimitive primitive_TIME; + +extern VTypeDef type_BOOLEAN; + +extern const VTypeArray primitive_BIT_VECTOR; +extern const VTypeArray primitive_BOOL_VECTOR; +extern const VTypeArray primitive_STDLOGIC_VECTOR; +extern const VTypeArray primitive_STRING; +extern const VTypeArray primitive_SIGNED; +extern const VTypeArray primitive_UNSIGNED; diff --git a/vhdlpp/subprogram.cc b/vhdlpp/subprogram.cc index 8d2f4f814..730dc3938 100644 --- a/vhdlpp/subprogram.cc +++ b/vhdlpp/subprogram.cc @@ -30,44 +30,70 @@ using namespace std; -Subprogram::Subprogram(perm_string nam, list*ports, - const VType*return_type) -: name_(nam), parent_(0), ports_(ports), return_type_(return_type), statements_(0) +SubprogramBody::SubprogramBody() + : statements_(NULL), header_(NULL) { } -Subprogram::~Subprogram() +SubprogramBody::~SubprogramBody() { } -void Subprogram::set_parent(const ScopeBase*par) +const InterfacePort*SubprogramBody::find_param(perm_string nam) const { - ivl_assert(*this, parent_ == 0); - parent_ = par; + if(!header_) + return NULL; + + return header_->find_param(nam); } -void Subprogram::set_program_body(list*stmt) +void SubprogramBody::set_statements(list*stmt) { ivl_assert(*this, statements_==0); statements_ = stmt; } -bool Subprogram::unbounded() const { - if(return_type_->is_unbounded()) - return true; +void SubprogramBody::write_to_stream(ostream&fd) const +{ + for (map::const_iterator cur = new_variables_.begin() + ; cur != new_variables_.end() ; ++cur) { + cur->second->write_to_stream(fd); + } - if(ports_) { - for(std::list::const_iterator it = ports_->begin(); - it != ports_->end(); ++it) { - if((*it)->type->is_unbounded()) - return true; - } - } + fd << "begin" << endl; - return false; + if (statements_) { + for (list::const_iterator cur = statements_->begin() + ; cur != statements_->end() ; ++cur) { + (*cur)->write_to_stream(fd); + } + } else { + fd << "--empty body" << endl; + } + fd << "end function;" << endl; } -bool Subprogram::compare_specification(Subprogram*that) const +SubprogramHeader::SubprogramHeader(perm_string nam, list*ports, + const VType*return_type) +: name_(nam), ports_(ports), return_type_(return_type), body_(NULL), parent_(NULL) +{ +} + +SubprogramHeader::~SubprogramHeader() +{ + delete body_; + + if(ports_) { + for(list::iterator it = ports_->begin(); + it != ports_->end(); ++it) + { + delete *it; + } + delete ports_; + } +} + +bool SubprogramHeader::compare_specification(SubprogramHeader*that) const { if (name_ != that->name_) return false; @@ -98,7 +124,7 @@ bool Subprogram::compare_specification(Subprogram*that) const return true; } -const InterfacePort*Subprogram::find_param(perm_string nam) const +const InterfacePort*SubprogramHeader::find_param(perm_string nam) const { if(!ports_) return NULL; @@ -112,7 +138,7 @@ const InterfacePort*Subprogram::find_param(perm_string nam) const return NULL; } -const VType*Subprogram::peek_param_type(int idx) const +const VType*SubprogramHeader::peek_param_type(int idx) const { if(!ports_ || idx < 0 || (size_t)idx >= ports_->size()) return NULL; @@ -123,7 +149,37 @@ const VType*Subprogram::peek_param_type(int idx) const return (*p)->type; } -Subprogram*Subprogram::make_instance(std::vector arguments, ScopeBase*scope) { +void SubprogramHeader::set_parent(const ScopeBase*par) +{ + ivl_assert(*this, !parent_); + parent_ = par; +} + +bool SubprogramHeader::unbounded() const { + if(return_type_ && return_type_->is_unbounded()) + return true; + + if(ports_) { + for(std::list::const_iterator it = ports_->begin(); + it != ports_->end(); ++it) { + if((*it)->type->is_unbounded()) + return true; + } + } + + return false; +} + +void SubprogramHeader::set_body(SubprogramBody*bdy) +{ + ivl_assert(*this, !body_); + body_ = bdy; + ivl_assert(*this, !bdy->header_); + bdy->header_ = this; +} + +SubprogramHeader*SubprogramHeader::make_instance(std::vector arguments, + ScopeBase*scope) const { assert(arguments.size() == ports_->size()); std::list*ports = new std::list; @@ -142,25 +198,31 @@ Subprogram*Subprogram::make_instance(std::vector arguments, ScopeBa char buf[80]; snprintf(buf, sizeof(buf), "__%s_%p", name_.str(), ports); perm_string new_name = lex_strings.make(buf); - Subprogram*instance = new Subprogram(new_name, ports, return_type_); + SubprogramHeader*instance = new SubprogramHeader(new_name, ports, return_type_); - // Copy variables - for(std::map::iterator it = new_variables_.begin(); - it != new_variables_.end(); ++it) { - Variable*v = new Variable(it->first, it->second->peek_type()->clone()); - instance->new_variables_[it->first] = v; + if(body_) { + SubprogramBody*body_inst = new SubprogramBody(); + + // Copy variables + for(std::map::iterator it = body_->new_variables_.begin(); + it != body_->new_variables_.end(); ++it) { + Variable*v = new Variable(it->first, it->second->peek_type()->clone()); + body_inst->new_variables_[it->first] = v; + } + + body_inst->set_statements(body_->statements_); + instance->set_parent(scope); + instance->set_body(body_inst); + instance->fix_return_type(); } - instance->set_parent(scope); - instance->set_program_body(statements_); - instance->fix_return_type(); scope->bind_subprogram(new_name, instance); return instance; } struct check_return_type : public SeqStmtVisitor { - check_return_type(const Subprogram*subp) : subp_(subp), ret_type_(NULL) {} + check_return_type(const SubprogramBody*subp) : subp_(subp), ret_type_(NULL) {} void operator() (SequentialStmt*s) { @@ -195,38 +257,44 @@ struct check_return_type : public SeqStmtVisitor { const VType*get_type() const { return ret_type_; } private: - const Subprogram*subp_; + const SubprogramBody*subp_; const VType*ret_type_; }; -void Subprogram::fix_return_type() +void SubprogramHeader::fix_return_type() { - if(!statements_) + if(!body_ || !body_->statements_) return; - check_return_type r(this); + check_return_type r(body_); - for (std::list::iterator s = statements_->begin() - ; s != statements_->end(); ++s) { + for (std::list::iterator s = body_->statements_->begin() + ; s != body_->statements_->end(); ++s) { (*s)->visit(r); } VType*return_type = const_cast(r.get_type()); if(return_type && !return_type->is_unbounded()) { // Let's check if the variable length can be evaluated without any scope. - // If not, then it is depends on information about e.g. function params + // If not, then it depends on information about e.g. function params if(return_type->is_variable_length(NULL)) { if(VTypeArray*arr = dynamic_cast(return_type)) - arr->evaluate_ranges(this); + arr->evaluate_ranges(body_); } return_type_ = return_type; } } -void Subprogram::write_to_stream(ostream&fd) const +void SubprogramHeader::write_to_stream(ostream&fd) const { - fd << " function " << name_ << "("; + if(return_type_) + fd << "function "; + else + fd << "procedure "; + + fd << name_; if (ports_ && ! ports_->empty()) { + fd << "("; list::const_iterator cur = ports_->begin(); InterfacePort*curp = *cur; fd << curp->name << " : "; @@ -236,44 +304,21 @@ void Subprogram::write_to_stream(ostream&fd) const fd << "; " << curp->name << " : "; curp->type->write_to_stream(fd); } + fd << ")"; + } + + if( return_type_) { + fd << " return "; + return_type_->write_to_stream(fd); } - fd << ") return "; - return_type_->write_to_stream(fd); - fd << ";" << endl; } -void Subprogram::write_to_stream_body(ostream&fd) const +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() { - 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 << " is" << endl; - - for (map::const_iterator cur = new_variables_.begin() - ; cur != new_variables_.end() ; ++cur) { - cur->second->write_to_stream(fd); - } - - fd << "begin" << endl; - - if (statements_) { - for (list::const_iterator cur = statements_->begin() - ; cur != statements_->end() ; ++cur) { - (*cur)->write_to_stream(fd); - } - } else { - fd << "--empty body" << endl; - } - fd << "end function;" << endl; } diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h index 22c49879e..0aa5dbdbc 100644 --- a/vhdlpp/subprogram.h +++ b/vhdlpp/subprogram.h @@ -27,63 +27,122 @@ # include "scope.h" # include # include +# include class InterfacePort; class SequentialStmt; class VType; +class SubprogramHeader; -class Subprogram : public LineInfo, public ScopeBase { +class SubprogramBody : public LineInfo, public ScopeBase { public: - Subprogram(perm_string name, std::list*ports, + SubprogramBody(); + ~SubprogramBody(); + + const InterfacePort*find_param(perm_string nam) const; + + void set_statements(std::list*statements); + inline bool empty_statements() const { return !statements_ || statements_->empty(); } + + int emit(ostream&out, Entity*ent, ScopeBase*scope); + + // Emit body 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; + + private: + std::list*statements_; + SubprogramHeader*header_; + + friend class SubprogramHeader; +}; + +class SubprogramHeader : public LineInfo { + public: + SubprogramHeader(perm_string name, std::list*ports, 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); - inline bool empty_program_body() const { return !statements_ || statements_->empty(); } + virtual ~SubprogramHeader(); // Return true if the specification (name, types, ports) // matches this subprogram and that subprogram. - bool compare_specification(Subprogram*that) const; + bool compare_specification(SubprogramHeader*that) const; const InterfacePort*find_param(perm_string nam) const; const VType*peek_param_type(int idx) const; const VType*peek_return_type() const { return return_type_; } - int emit(ostream&out, Entity*ent, ScopeBase*scope); + void set_parent(const ScopeBase*par); + inline const ScopeBase*get_parent() const { return parent_; } - // Emit a definition as it would show up in a package. - int emit_package(std::ostream&fd) const; + // Checks if either return type or parameters are unbounded vectors. + bool unbounded() const; - void write_to_stream(std::ostream&fd) const; - void write_to_stream_body(std::ostream&fd) const; - void dump(std::ostream&fd) const; + // 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() 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. - Subprogram*make_instance(std::vector arguments, ScopeBase*scope); + SubprogramHeader*make_instance(std::vector arguments, ScopeBase*scope) const; - // Checks if either return type or parameters are unbounded vectors. - bool unbounded() const; + // Emit header as it would show up in a package. + int emit_package(std::ostream&fd) const; - private: + void write_to_stream(std::ostream&fd) const; + void dump(std::ostream&fd) const; + + 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. void fix_return_type(); + // Procedure/function name perm_string name_; - const ScopeBase*parent_; + std::list*ports_; const VType*return_type_; - std::list*statements_; + SubprogramBody*body_; + 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 c2ae47cd8..6c880e90f 100644 --- a/vhdlpp/subprogram_emit.cc +++ b/vhdlpp/subprogram_emit.cc @@ -25,19 +25,42 @@ using namespace std; -int Subprogram::emit_package(ostream&fd) const +int SubprogramBody::emit_package(ostream&fd) const +{ + int errors = 0; + + for (map::const_iterator cur = new_variables_.begin() + ; cur != new_variables_.end() ; ++cur) { + // Workaround to enable reg_flag for variables + cur->second->count_ref_sequ(); + errors += cur->second->emit(fd, NULL, NULL); + } + + if (statements_) { + for (list::const_iterator cur = statements_->begin() + ; cur != statements_->end() ; ++cur) { + errors += (*cur)->emit(fd, NULL, const_cast(this)); + } + } else { + fd << " begin /* empty body */ end" << endl; + } + + return errors; +} + +int SubprogramHeader::emit_package(ostream&fd) const { int errors = 0; if (return_type_) { fd << "function "; return_type_->emit_def(fd, empty_perm_string); - fd << " " << name_; - fd << "("; } else { - fd << "task " << name_ << ";" << endl; + fd << "task"; } + fd << " \\" << name_ << " ("; + for (list::const_iterator cur = ports_->begin() ; cur != ports_->end() ; ++cur) { if (cur != ports_->begin()) @@ -63,21 +86,8 @@ int Subprogram::emit_package(ostream&fd) const fd << ");" << endl; - for (map::const_iterator cur = new_variables_.begin() - ; cur != new_variables_.end() ; ++cur) { - // Workaround to enable reg_flag for variables - cur->second->count_ref_sequ(); - errors += cur->second->emit(fd, NULL, NULL); - } - - if (statements_) { - for (list::const_iterator cur = statements_->begin() - ; cur != statements_->end() ; ++cur) { - errors += (*cur)->emit(fd, NULL, const_cast(this)); - } - } else { - fd << " begin /* empty body */ end" << endl; - } + if (body_) + body_->emit_package(fd); if (return_type_) fd << "endfunction" << endl; @@ -86,3 +96,31 @@ int Subprogram::emit_package(ostream&fd) const return errors; } + +int SubprogramHeader::emit_name(const std::vector&, + std::ostream&out, Entity*, ScopeBase*) const +{ + out << "\\" << name_; + return 0; +} + +int SubprogramHeader::emit_args(const std::vector&argv, + std::ostream&out, Entity*ent, ScopeBase*scope) const +{ + int errors = 0; + + for (size_t idx = 0; idx < argv.size() ; idx += 1) { + if (idx > 0) out << ", "; + errors += argv[idx]->emit(out, ent, scope); + } + + 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/vsignal.cc b/vhdlpp/vsignal.cc index 043c2b1a9..38516dbaf 100644 --- a/vhdlpp/vsignal.cc +++ b/vhdlpp/vsignal.cc @@ -66,7 +66,7 @@ int Signal::emit(ostream&out, Entity*ent, ScopeBase*scope) return errors; } -int Variable::emit(ostream&out, Entity*, ScopeBase*) +int Variable::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; @@ -75,6 +75,12 @@ int Variable::emit(ostream&out, Entity*, ScopeBase*) if (peek_refcnt_sequ_() > 0 || !peek_type()->can_be_packed()) decl.reg_flag = true; errors += decl.emit(out, peek_name()); + + Expression*init_expr = peek_init_expr(); + if (init_expr) { + out << " = "; + init_expr->emit(out, ent, scope); + } out << ";" << endl; return errors; } diff --git a/vhdlpp/vsignal.h b/vhdlpp/vsignal.h index d2bfdbcd0..6aa225d14 100644 --- a/vhdlpp/vsignal.h +++ b/vhdlpp/vsignal.h @@ -77,7 +77,7 @@ class Signal : public SigVarBase { class Variable : public SigVarBase { public: - Variable(perm_string name, const VType*type); + Variable(perm_string name, const VType*type, Expression*init_expr = NULL); int emit(ostream&out, Entity*ent, ScopeBase*scope); void write_to_stream(std::ostream&fd); @@ -93,8 +93,8 @@ inline Signal::Signal(perm_string name, const VType*type, Expression*init_expr) { } -inline Variable::Variable(perm_string name, const VType*type) -: SigVarBase(name, type, 0) +inline Variable::Variable(perm_string name, const VType*type, Expression*init_expr) +: SigVarBase(name, type, init_expr) { } diff --git a/vhdlpp/vtype.cc b/vhdlpp/vtype.cc index 4dc97199a..0e6c1b47d 100644 --- a/vhdlpp/vtype.cc +++ b/vhdlpp/vtype.cc @@ -55,9 +55,6 @@ VTypePrimitive::~VTypePrimitive() void VTypePrimitive::show(ostream&out) const { switch (type_) { - case BOOLEAN: - out << "BOOLEAN"; - break; case BIT: out << "BIT"; break; @@ -85,7 +82,6 @@ void VTypePrimitive::show(ostream&out) const int VTypePrimitive::get_width(ScopeBase*) const { switch(type_) { - case BOOLEAN: case BIT: case STDLOGIC: return 1; @@ -266,12 +262,11 @@ bool VTypeArray::is_variable_length(ScopeBase*scope) const { void VTypeArray::evaluate_ranges(ScopeBase*scope) { for(std::vector::iterator it = ranges_.begin(); it != ranges_.end(); ++it ) { int64_t lsb_val = -1, msb_val = -1; - bool dir = it->is_downto(); if(it->msb()->evaluate(scope, msb_val) && it->lsb()->evaluate(scope, lsb_val)) { assert(lsb_val >= 0); assert(msb_val >= 0); - *it = range_t(new ExpInteger(msb_val), new ExpInteger(lsb_val), dir); + *it = range_t(new ExpInteger(msb_val), new ExpInteger(lsb_val), msb_val > lsb_val); } } } diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index 0756ff68b..9ff448dd5 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -156,7 +156,7 @@ class VTypeERROR : public VType { class VTypePrimitive : public VType { public: - enum type_t { BOOLEAN, BIT, INTEGER, NATURAL, REAL, STDLOGIC, CHARACTER, TIME }; + enum type_t { BIT, INTEGER, NATURAL, REAL, STDLOGIC, CHARACTER, TIME }; public: VTypePrimitive(type_t tt, bool packed = false); @@ -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 @@ -265,6 +256,8 @@ class VTypeArray : public VType { private: int emit_with_dims_(std::ostream&out, bool packed, perm_string name) const; + // Handles a few special types of array (*_vector, string types). + bool write_special_case(std::ostream&out) const; void write_range_to_stream_(std::ostream&fd) const; const VType*etype_; @@ -363,6 +356,8 @@ class VTypeDef : public VType { VType*clone() const { return new VTypeDef(*this); } + bool type_match(const VType*that) const; + inline perm_string peek_name() const { return name_; } // If the type is not given a definition in the constructor, diff --git a/vhdlpp/vtype_emit.cc b/vhdlpp/vtype_emit.cc index cfb8f6390..d54cce23a 100644 --- a/vhdlpp/vtype_emit.cc +++ b/vhdlpp/vtype_emit.cc @@ -132,7 +132,7 @@ int VTypeArray::emit_with_dims_(std::ostream&out, bool packed, perm_string name) int VTypeEnum::emit_def(ostream&out, perm_string name) const { int errors = 0; - out << "enum {"; + out << "enum integer {"; assert(names_.size() >= 1); out << "\\" << names_[0] << " "; for (size_t idx = 1 ; idx < names_.size() ; idx += 1) @@ -148,9 +148,6 @@ int VTypePrimitive::emit_primitive_type(ostream&out) const { int errors = 0; switch (type_) { - case BOOLEAN: - out << "boolean"; - break; case BIT: out << "bit"; break; @@ -167,7 +164,7 @@ int VTypePrimitive::emit_primitive_type(ostream&out) const out << "real"; break; case CHARACTER: - out << "char"; + out << "byte"; break; case TIME: out << "time"; @@ -229,10 +226,9 @@ int VTypeDef::emit_def(ostream&out, perm_string name) const int VTypeDef::emit_decl(ostream&out, perm_string name, bool reg_flag) const { int errors = 0; - if (reg_flag) - out << "reg "; - else - out << "wire "; + + if (!dynamic_cast(type_)) + out << (reg_flag ? "reg " : "wire "); if(dynamic_cast(type_)) { errors += type_->emit_def(out, name); diff --git a/vhdlpp/vtype_match.cc b/vhdlpp/vtype_match.cc index e0559d24d..86c8f90ff 100644 --- a/vhdlpp/vtype_match.cc +++ b/vhdlpp/vtype_match.cc @@ -22,5 +22,21 @@ bool VType::type_match(const VType*that) const { - return this == that; + if(this == that) + return true; + + if(const VTypeDef*tdef = dynamic_cast(that)) { + if(type_match(tdef->peek_definition())) + return true; + } + + return false; +} + +bool VTypeDef::type_match(const VType*that) const +{ + if(VType::type_match(that)) + return true; + + return VType::type_match(type_); } diff --git a/vhdlpp/vtype_stream.cc b/vhdlpp/vtype_stream.cc index 9f8b6c689..1394ccd06 100644 --- a/vhdlpp/vtype_stream.cc +++ b/vhdlpp/vtype_stream.cc @@ -18,7 +18,7 @@ */ # define __STDC_LIMIT_MACROS -# include "vtype.h" +# include "std_types.h" # include "expression.h" # include # include @@ -38,20 +38,8 @@ void VType::write_type_to_stream(ostream&fd) const void VTypeArray::write_to_stream(ostream&fd) const { - // Special cases: std_logic_vector & string - if (etype_ == &primitive_STDLOGIC) { - fd << "std_logic_vector"; - if (!ranges_.empty() && !ranges_[0].is_box()) { - write_range_to_stream_(fd); - } - return; - } else if (etype_ == &primitive_CHARACTER) { - fd << "string"; - if (!ranges_.empty() && !ranges_[0].is_box()) { - write_range_to_stream_(fd); - } - return; - } + if(write_special_case(fd)) + return; bool typedefed = false; if(const VTypeDef*tdef = dynamic_cast(etype_)) { @@ -96,26 +84,37 @@ void VTypeArray::write_range_to_stream_(std::ostream&fd) const fd << ") "; } +bool VTypeArray::write_special_case(std::ostream&fd) const +{ + if(this == &primitive_SIGNED) { + fd << "signed"; + } else if(this == &primitive_UNSIGNED) { + fd << "unsigned"; + } else if(etype_ == &primitive_STDLOGIC) { + fd << "std_logic_vector"; + } else if(etype_ == &primitive_BIT) { + fd << "bit_vector"; + } else if(etype_ == &primitive_CHARACTER) { + fd << "string"; + } else { + return false; + } + + if(!ranges_.empty() && !ranges_[0].is_box()) { + write_range_to_stream_(fd); + } + + return true; +} + void VTypeArray::write_type_to_stream(ostream&fd) const { - // Special case: std_logic_vector - if (etype_ == &primitive_STDLOGIC) { - fd << "std_logic_vector"; - if (! ranges_.empty() && ! ranges_[0].is_box()) { - write_range_to_stream_(fd); - } - return; - } - else if (etype_ == &primitive_CHARACTER) { - fd << "string"; - if (! ranges_.empty() && ! ranges_[0].is_box()) { - write_range_to_stream_(fd); - } - return; - } + if(write_special_case(fd)) + return; fd << "array "; + // Unbounded array if (! ranges_.empty()) { assert(ranges_.size() < 2); if (ranges_[0].is_box()) { @@ -165,9 +164,6 @@ void VTypePrimitive::write_to_stream(ostream&fd) const case CHARACTER: fd << "character"; break; - case BOOLEAN: - fd << "boolean"; - break; case TIME: fd << "time"; break; @@ -183,7 +179,7 @@ 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 (start_==0 && end_==INT64_MAX && tmp->type()==VTypePrimitive::INTEGER) { + if (tmp->type()==VTypePrimitive::NATURAL) { fd << "natural"; return; } diff --git a/vpi/vhdl_table.c b/vpi/vhdl_table.c index a6dcac300..a1b895df8 100644 --- a/vpi/vhdl_table.c +++ b/vpi/vhdl_table.c @@ -156,16 +156,16 @@ static PLI_INT32 ivlh_attribute_event_calltf(ICARUS_VPI_CONST PLI_BYTE8*data) rval.value.scalar = vpi1; - // Detect if there was any change + // Detect if change occured in this moment if (mon->last_event.high != tnow.high) rval.value.scalar = vpi0; if (mon->last_event.low != tnow.low) rval.value.scalar = vpi0; // Determine the edge, if required - if (type == RISING_EDGE && mon->last_value.value.scalar == vpi0) + if (type == RISING_EDGE && mon->last_value.value.scalar != vpi1) rval.value.scalar = vpi0; - else if (type == FALLING_EDGE && mon->last_value.value.scalar == vpi1) + else if (type == FALLING_EDGE && mon->last_value.value.scalar != vpi0) rval.value.scalar = vpi0; }