diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index b35c28731..7d72dd0b5 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -55,6 +55,27 @@ void dump_design_entities(ostream&file) } } +void ComponentBase::dump_generics(ostream&out, int indent) const +{ + if (parms_.empty()) { + out << setw(indent) << "" << "No generics" << endl; + } else { + out << setw(indent) << "" << "GENERICS:" << endl; + for (vector::const_iterator cur = parms_.begin() + ; cur != parms_.end() ; ++cur) { + InterfacePort*item = *cur; + out << setw(indent+2) << "" << item->name + << " : " << item->mode + << ", type="; + if (item->type) + item->type->show(out); + else + out << ""; + out << ", file=" << item->get_fileline() << endl; + } + } +} + void ComponentBase::dump_ports(ostream&out, int indent) const { if (ports_.empty()) { @@ -122,6 +143,7 @@ void Scope::dump_scope(ostream&out) const for (map::const_iterator cur = old_components_.begin() ; cur != old_components_.end() ; ++cur) { out << " component " << cur->first << " is" << endl; + cur->second->dump_generics(out); cur->second->dump_ports(out); out << " end component " << cur->first << endl; } diff --git a/vhdlpp/entity.cc b/vhdlpp/entity.cc index 411596178..68d3c6280 100644 --- a/vhdlpp/entity.cc +++ b/vhdlpp/entity.cc @@ -63,6 +63,16 @@ const InterfacePort* ComponentBase::find_port(perm_string my_name) const return 0; } +const InterfacePort* ComponentBase::find_generic(perm_string my_name) const +{ + for (size_t idx = 0 ; idx < parms_.size() ; idx += 1) { + if (parms_[idx]->name == my_name) + return parms_[idx]; + } + + return 0; +} + Entity::Entity(perm_string name) : ComponentBase(name) { diff --git a/vhdlpp/entity.h b/vhdlpp/entity.h index 05e24f4c4..faf66af8b 100644 --- a/vhdlpp/entity.h +++ b/vhdlpp/entity.h @@ -60,7 +60,9 @@ class ComponentBase : public LineInfo { // Entities have names. perm_string get_name() const { return name_; } + const InterfacePort* find_port(perm_string by_name) const; + const InterfacePort* find_generic(perm_string by_name) const; // Declare the ports for the entity. The parser calls this // method with a list of interface elements that were parsed @@ -73,14 +75,12 @@ class ComponentBase : public LineInfo { void write_to_stream(std::ostream&fd) const; public: + void dump_generics(std::ostream&out, int indent =0) const; void dump_ports(std::ostream&out, int indent = 0) const; - protected: - // This is really only used by the Entity derived class. - const std::vector&get_ports() const { return ports_; } - private: perm_string name_; + protected: std::vector parms_; std::vector ports_; }; diff --git a/vhdlpp/entity_elaborate.cc b/vhdlpp/entity_elaborate.cc index 586c9041d..c37d2dea4 100644 --- a/vhdlpp/entity_elaborate.cc +++ b/vhdlpp/entity_elaborate.cc @@ -87,10 +87,8 @@ int Entity::elaborate() int Entity::elaborate_ports_(void) { int errors = 0; - const std::vector&ports = get_ports(); - - for (std::vector::const_iterator cur = ports.begin() - ; cur != ports.end() ; ++cur) { + for (std::vector::const_iterator cur = ports_.begin() + ; cur != ports_.end() ; ++cur) { InterfacePort*cur_port = *cur; diff --git a/vhdlpp/entity_emit.cc b/vhdlpp/entity_emit.cc index 6ffd54b69..92d652562 100644 --- a/vhdlpp/entity_emit.cc +++ b/vhdlpp/entity_emit.cc @@ -22,6 +22,7 @@ # include # include # include +# include int emit_entities(void) { @@ -39,16 +40,30 @@ int Entity::emit(ostream&out) { int errors = 0; - const std::vector&ports = get_ports(); + out << "module "; + // If there are generics, emit them + if (parms_.size() > 0) { + out << "#("; + for (vector::const_iterator cur = parms_.begin() + ; cur != parms_.end() ; ++cur) { + const InterfacePort*curp = *cur; + if (cur != parms_.begin()) + out << ", "; + out << "parameter \\" << curp->name << " = "; + ivl_assert(*this, curp->expr); + errors += curp->expr->emit(out, this, 0); + } + out << ") "; + } - out << "module " << get_name(); + out << get_name(); // If there are ports, emit them. - if (ports.size() > 0) { + if (ports_.size() > 0) { out << "("; const char*sep = 0; - for (vector::const_iterator cur = ports.begin() - ; cur != ports.end() ; ++cur) { + for (vector::const_iterator cur = ports_.begin() + ; cur != ports_.end() ; ++cur) { InterfacePort*port = *cur; VType::decl_t&decl = declarations_[port->name]; diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index cd8e71469..d5bee38e1 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -42,11 +42,6 @@ void Expression::set_type(const VType*typ) type_ = typ; } -bool Expression::evaluate(ScopeBase*, int64_t&) const -{ - return false; -} - bool Expression::symbolic_compare(const Expression*) const { cerr << get_fileline() << ": internal error: " @@ -87,40 +82,6 @@ ExpAttribute::~ExpAttribute() delete base_; } -bool ExpAttribute::evaluate(ScopeBase*, int64_t&val) const -{ - /* Special Case: The length attribute can be calculated all - the down to a literal integer at compile time, and all it - needs is the type of the base expression. (The base - expression doesn't even need to be evaluated.) */ - if (name_ == "length") { - const VType*base_type = base_->peek_type(); - //if (base_type == 0) - // base_type = base_->probe_type(ent,arc); - - ivl_assert(*this, base_type); - - const VTypeArray*arr = dynamic_cast(base_type); - if (arr == 0) { - cerr << get_fileline() << ": error: " - << "Cannot apply the 'length attribute to non-array objects" - << endl; - return false; - } - - int64_t size = 1; - for (size_t idx = 0 ; idx < arr->dimensions() ; idx += 1) { - const VTypeArray::range_t&dim = arr->dimension(idx); - ivl_assert(*this, ! dim.is_box()); - size *= 1 + labs(dim.msb() - dim.lsb()); - } - val = size; - return true; - } - - return false; -} - ExpBinary::ExpBinary(Expression*op1, Expression*op2) : operand1_(op1), operand2_(op2) { @@ -402,18 +363,6 @@ const char* ExpName::name() const return name_; } -bool ExpName::evaluate(ScopeBase*scope, int64_t&val) const -{ - const VType*type; - Expression*exp; - - bool rc = scope->find_constant(name_, type, exp); - if (rc == false) - return false; - - return exp->evaluate(scope, val); -} - ExpRelation::ExpRelation(ExpRelation::fun_t ty, Expression*op1, Expression*op2) : ExpBinary(op1, op2), fun_(ty) { diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index d9cdea674..a05e3c5dc 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -80,6 +80,8 @@ class Expression : public LineInfo { // argument if the evaluation works, or return false if it // cannot be done. virtual bool evaluate(ScopeBase*scope, int64_t&val) const; + virtual bool evaluate(Entity*ent, Architecture*arc, int64_t&val) const; + // The symbolic compare returns true if the two expressions // are equal without actually calculating the value. @@ -266,6 +268,7 @@ class ExpAttribute : public Expression { int emit(ostream&out, Entity*ent, Architecture*arc); // Some attributes can be evaluated at compile time bool evaluate(ScopeBase*scope, int64_t&val) const; + bool evaluate(Entity*ent, Architecture*arc, int64_t&val) const; void dump(ostream&out, int indent = 0) const; private: @@ -427,6 +430,7 @@ class ExpName : public Expression { int emit(ostream&out, Entity*ent, Architecture*arc); bool is_primary(void) const; bool evaluate(ScopeBase*scope, int64_t&val) const; + bool evaluate(Entity*ent, Architecture*arc, int64_t&val) const; bool symbolic_compare(const Expression*that) const; void dump(ostream&out, int indent = 0) const; const char* name() const; diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 35d50413f..5e3a88fbc 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -30,7 +30,7 @@ using namespace std; int Expression::elaborate_lval(Entity*, Architecture*, bool) { - cerr << get_fileline() << ": error: Expression is not a valie l-value." << endl; + cerr << get_fileline() << ": error: Expression is not a valid l-value." << endl; return 1; } @@ -57,6 +57,13 @@ int ExpName::elaborate_lval(Entity*ent, Architecture*arc, bool is_sequ) found_type = cur->type; + } else if (ent->find_generic(name_)) { + + cerr << get_fileline() << ": error: Assignment to generic " + << name_ << " from entity " + << ent->get_name() << "." << endl; + return 1; + } else if (Signal*sig = arc->find_signal(name_)) { // Tell the target signal that this may be a sequential l-value. if (is_sequ) sig->count_ref_sequ(); @@ -93,8 +100,10 @@ int ExpName::elaborate_lval(Entity*ent, Architecture*arc, bool is_sequ) flag = lsb_->evaluate(arc, use_lsb); ivl_assert(*this, flag); + Expression*exp_msb = new ExpInteger(use_msb); + Expression*exp_lsb = new ExpInteger(use_lsb); vector use_dims (1); - use_dims[0] = VTypeArray::range_t(use_msb, use_lsb); + use_dims[0] = VTypeArray::range_t(exp_msb, exp_lsb); found_type = new VTypeArray(array->element_type(), use_dims); } } @@ -366,8 +375,15 @@ int ExpLogical::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) const VType* ExpName::probe_type(Entity*ent, Architecture*arc) const { - if (const InterfacePort*cur = ent->find_port(name_)) + if (const InterfacePort*cur = ent->find_port(name_)) { + ivl_assert(*this, cur->type); return cur->type; + } + + if (const InterfacePort*cur = ent->find_generic(name_)) { + ivl_assert(*this, cur->type); + return cur->type; + } if (Signal*sig = arc->find_signal(name_)) return sig->peek_type(); diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 02dc5fae3..1777da7fa 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -87,11 +87,38 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V const VTypeArray::range_t&rang = atype->dimension(0); assert(! rang.is_box()); - int asize = abs(rang.msb() - rang.lsb()) + 1; + int64_t use_msb; + int64_t use_lsb; + bool rc_msb, rc_lsb; + rc_msb = rang.msb()->evaluate(ent, arc, use_msb); + rc_lsb = rang.lsb()->evaluate(ent, arc, use_lsb); - out << "{" << asize << "{"; - errors += aggregate_[0].expr->emit(out, ent, arc); - out << "}}"; + if (rc_msb && rc_lsb) { + int asize = abs(use_msb - use_lsb) + 1; + out << "{" << asize << "{"; + errors += aggregate_[0].expr->emit(out, ent, arc); + out << "}}"; + } else { + out << "{("; + if (rc_msb) { + out << use_msb; + } else { + out << "("; + errors += rang.msb()->emit(out, ent, arc); + out << ")"; + } + if (rc_lsb && use_lsb==0) { + } else if (rc_lsb) { + out << "-" << use_lsb; + } else { + out << "-("; + errors += rang.lsb()->emit(out, ent, arc); + out << ")"; + } + out << "+1){"; + errors += aggregate_[0].expr->emit(out, ent, arc); + out << "}}"; + } return errors; } @@ -110,7 +137,7 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V Expression*tmp = aggregate_[idx].choice->simple_expression(false); int64_t tmp_val; - if (! tmp->evaluate(arc, tmp_val)) { + if (! tmp->evaluate(ent, arc, tmp_val)) { cerr << tmp->get_fileline() << ": error: Unable to evaluate aggregate choice expression." << endl; errors += 1; continue; @@ -119,16 +146,22 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V element_map[tmp_val] = &aggregate_[idx]; } - ivl_assert(*this, rang.msb() >= rang.lsb()); + int64_t use_msb, use_lsb; + bool rc; + rc = rang.msb()->evaluate(ent, arc, use_msb); + ivl_assert(*this, rc); + rc = rang.lsb()->evaluate(ent, arc, use_lsb); + ivl_assert(*this, rc); + ivl_assert(*this, use_msb >= use_lsb); out << "{"; - for (int idx = rang.msb() ; idx >= rang.lsb() ; idx -= 1) { + for (int64_t idx = use_msb ; idx >= use_lsb ; idx -= 1) { choice_element*cur = element_map[idx]; if (cur == 0) cur = element_other; ivl_assert(*this, cur != 0); - if (idx < rang.msb()) + if (idx < use_msb) out << ", "; errors += cur->expr->emit(out, ent, arc); } @@ -154,7 +187,7 @@ int ExpAttribute::emit(ostream&out, Entity*ent, Architecture*arc) expression doesn't even need to be evaluated.) */ if (name_ == "length") { int64_t val; - bool rc = evaluate(arc, val); + bool rc = evaluate(ent, arc, val); out << val; if (rc) return errors; @@ -356,7 +389,7 @@ int ExpFunc::emit(ostream&out, Entity*ent, Architecture*arc) } else if (name_ == "to_unsigned" && argv_.size() == 2) { int64_t use_size; - bool rc = argv_[1]->evaluate(arc, use_size); + bool rc = argv_[1]->evaluate(ent, arc, use_size); ivl_assert(*this, rc); out << "$unsigned(" << use_size << "'("; diff --git a/vhdlpp/expression_evaluate.cc b/vhdlpp/expression_evaluate.cc new file mode 100644 index 000000000..3596e9fd5 --- /dev/null +++ b/vhdlpp/expression_evaluate.cc @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "expression.h" +# include "architec.h" +# include + +bool Expression::evaluate(ScopeBase*, int64_t&) const +{ + return false; +} + +bool Expression::evaluate(Entity*, Architecture*arc, int64_t&val) const +{ + return evaluate(arc, val); +} + + +bool ExpAttribute::evaluate(ScopeBase*, int64_t&val) const +{ + /* Special Case: The length attribute can be calculated all + the down to a literal integer at compile time, and all it + needs is the type of the base expression. (The base + expression doesn't even need to be evaluated.) */ + if (name_ == "length") { + const VType*base_type = base_->peek_type(); + //if (base_type == 0) + // base_type = base_->probe_type(ent,arc); + + ivl_assert(*this, base_type); + + const VTypeArray*arr = dynamic_cast(base_type); + if (arr == 0) { + cerr << get_fileline() << ": error: " + << "Cannot apply the 'length attribute to non-array objects" + << endl; + return false; + } + + int64_t size = 1; + for (size_t idx = 0 ; idx < arr->dimensions() ; idx += 1) { + const VTypeArray::range_t&dim = arr->dimension(idx); + ivl_assert(*this, ! dim.is_box()); + size *= 1 + labs(dim.msb() - dim.lsb()); + } + val = size; + return true; + } + + return false; +} + +bool ExpAttribute::evaluate(Entity*, Architecture*arc, int64_t&val) const +{ + return evaluate(arc, val); +} + +bool ExpName::evaluate(ScopeBase*scope, int64_t&val) const +{ + const VType*type; + Expression*exp; + + bool rc = scope->find_constant(name_, type, exp); + if (rc == false) + return false; + + return exp->evaluate(scope, val); +} + +bool ExpName::evaluate(Entity*ent, Architecture*arc, int64_t&val) const +{ + const InterfacePort*gen = ent->find_generic(name_); + if (gen) { + cerr << get_fileline() << ": sorry: I don't necessarily handle generic overrides." << endl; + + // Evaluate the default expression and use that. + if (gen->expr) + return gen->expr->evaluate(ent, arc, val); + } + + return evaluate(arc, val); +} diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index 9aaed533d..08b312fa8 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -17,6 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ +# define __STDC_LIMIT_MACROS # include "parse_misc.h" # include "compiler.h" # include "package.h" @@ -24,6 +25,7 @@ # include # include # include +# include # include # include @@ -312,6 +314,8 @@ const VTypePrimitive* primitive_BIT = new VTypePrimitive(VTypePrimitive::BI const VTypePrimitive* primitive_INTEGER = new VTypePrimitive(VTypePrimitive::INTEGER); const VTypePrimitive* primitive_STDLOGIC = new VTypePrimitive(VTypePrimitive::STDLOGIC); +const VTypeRange* primitive_NATURAL = new VTypeRange(primitive_INTEGER, INT64_MAX, 0); + const VTypeArray* primitive_BIT_VECTOR = new VTypeArray(primitive_BIT, vector (1)); const VTypeArray* primitive_BOOL_VECTOR = new VTypeArray(primitive_BOOLEAN, vector (1)); @@ -322,6 +326,7 @@ void generate_global_types(ActiveScope*res) res->bind_name(perm_string::literal("integer"), primitive_INTEGER); res->bind_name(perm_string::literal("std_logic"), primitive_STDLOGIC); res->bind_name(perm_string::literal("bit_vector"),primitive_BOOL_VECTOR); + res->bind_name(perm_string::literal("natural"), primitive_NATURAL); } void library_set_work_path(const char*path) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index fdbc55a62..94694a0b9 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -43,6 +43,7 @@ # include # include # include "parse_types.h" +# include # include inline void FILE_NAME(LineInfo*tmp, const struct yyltype&where) @@ -1095,6 +1096,7 @@ interface_element port->name = *(cur); port->type = $4; port->expr = $5; + ivl_assert(*port, port->type); tmp->push_back(port); } delete $1; @@ -1746,6 +1748,9 @@ subtype_declaration subtype_indication : IDENTIFIER { const VType*tmp = parse_type_by_name(lex_strings.make($1)); + if (tmp == 0) { + errormsg(@1, "Can't find type name `%s'\n", $1); + } delete[]$1; $$ = tmp; } diff --git a/vhdlpp/parse_misc.cc b/vhdlpp/parse_misc.cc index 7b4c49e36..045988f6c 100644 --- a/vhdlpp/parse_misc.cc +++ b/vhdlpp/parse_misc.cc @@ -66,7 +66,7 @@ void bind_architecture_to_entity(const char*ename, Architecture*arch) } const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name, - ScopeBase*scope, + ScopeBase* /* scope */, Expression*array_left, bool /* downto*/ , Expression*array_right) @@ -89,17 +89,7 @@ const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name, // For now, I only know how to handle 1 dimension assert(base_array->dimensions() == 1); - int64_t left_val; - int64_t right_val; - bool rc = array_left->evaluate(scope, left_val); - if (rc == false) - return 0; - - rc = array_right->evaluate(scope, right_val); - if (rc == false) - return 0; - - range[0] = VTypeArray::range_t(left_val, right_val); + range[0] = VTypeArray::range_t(array_left, array_right); VTypeArray*subtype = new VTypeArray(base_array->element_type(), range, base_array->signed_vector()); return subtype; diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index 83708bca1..92e49b821 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -195,10 +195,10 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, Architecture*arc) ivl_assert(*this, range_); int64_t start_val; - bool start_rc = range_->msb()->evaluate(arc, start_val); + bool start_rc = range_->msb()->evaluate(ent, arc, start_val); int64_t finish_val; - bool finish_rc = range_->lsb()->evaluate(arc, finish_val); + bool finish_rc = range_->lsb()->evaluate(ent, arc, finish_val); ivl_assert(*this, start_rc); ivl_assert(*this, finish_rc); diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index 0fe6e835a..c315de95f 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -26,6 +26,8 @@ # include # include "StringHeap.h" +class Expression; + /* * A description of a VHDL type consists of a graph of VType * objects. Derived types are specific kinds of types, and those that @@ -123,17 +125,17 @@ class VTypeArray : public VType { public: class range_t { public: - range_t() : msb_(INT_MAX), lsb_(INT_MIN) { } - range_t(int m, int l) : msb_(m), lsb_(l) { } + range_t() : msb_(0), lsb_(0) { } + range_t(Expression*m, Expression*l) : msb_(m), lsb_(l) { } - bool is_box() const { return msb_==INT_MAX && lsb_==INT_MIN; } + bool is_box() const { return msb_==0 && lsb_==0; } - int msb() const { return msb_; } - int lsb() const { return lsb_; } + Expression* msb() const { return msb_; } + Expression* lsb() const { return lsb_; } private: - int msb_; - int lsb_; + Expression* msb_; + Expression* lsb_; }; public: diff --git a/vhdlpp/vtype_emit.cc b/vhdlpp/vtype_emit.cc index d661bc689..d5f67a6b0 100644 --- a/vhdlpp/vtype_emit.cc +++ b/vhdlpp/vtype_emit.cc @@ -19,7 +19,8 @@ # include "vtype.h" -# include +# include "expression.h" +# include # include # include @@ -43,7 +44,11 @@ int VTypeArray::emit_def(ostream&out, perm_string name) const if (signed_flag_) out << "signed "; - out << "[" << dimension(0).msb() << ":" << dimension(0).lsb() << "] "; + out << "["; + errors += dimension(0).msb()->emit(out, 0, 0); + out << ":"; + errors += dimension(0).lsb()->emit(out, 0, 0); + out << "] "; out << "\\" << name << " ";