diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 917a6c28a..dcea7f470 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -567,7 +567,7 @@ const VType* ExpAttribute::probe_type(Entity*ent, Architecture*arc) const { base_->probe_type(ent, arc); - if (name_ == "length") { + if (name_ == "length" || name_ == "left" || name_ == "right") { return &primitive_INTEGER; } diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 78f299b3a..a84122c02 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -313,8 +313,8 @@ int ExpAttribute::emit(ostream&out, Entity*ent, Architecture*arc) return errors; } - /* Special Case: The length attribute can be calculated all - the down to a literal integer at compile time, and all it + /* Special Case: The length,left & right attributes 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") { @@ -322,9 +322,13 @@ int ExpAttribute::emit(ostream&out, Entity*ent, Architecture*arc) errors += base_->emit(out, ent, arc); out << ")"; return errors; + } else if (name_=="left" || name_=="right") { + out << "$" << name_ << "("; + errors += base_->emit(out, ent, arc); + out << ")"; + return errors; } - out << "$ivl_attribute("; errors += base_->emit(out, ent, arc); out << ", \"" << name_ << "\")"; diff --git a/vhdlpp/expression_evaluate.cc b/vhdlpp/expression_evaluate.cc index 56b631006..0bdb8bded 100644 --- a/vhdlpp/expression_evaluate.cc +++ b/vhdlpp/expression_evaluate.cc @@ -110,8 +110,32 @@ bool ExpAttribute::evaluate(ScopeBase*, int64_t&val) const return false; } -bool ExpAttribute::evaluate(Entity*, Architecture*arc, int64_t&val) const +bool ExpAttribute::evaluate(Entity*ent, Architecture*arc, int64_t&val) const { + if (name_ == "left" || name_ == "right") { + 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 'left attribute to non-array objects" + << endl; + return false; + } + + ivl_assert(*this, arr->dimensions() == 1); + if(name_ == "left") + arr->dimension(0).msb()->evaluate(ent, arc, val); + else + arr->dimension(0).lsb()->evaluate(ent, arc, val); + + return true; + } + return evaluate(arc, val); } diff --git a/vhdlpp/expression_stream.cc b/vhdlpp/expression_stream.cc index a37fea2ed..103e210ae 100644 --- a/vhdlpp/expression_stream.cc +++ b/vhdlpp/expression_stream.cc @@ -111,9 +111,10 @@ void ExpArithmetic::write_to_stream(ostream&out) out << ")"; } -void ExpAttribute::write_to_stream(ostream&) +void ExpAttribute::write_to_stream(ostream&fd) { - ivl_assert(*this, !"Not supported"); + base_->write_to_stream(fd); + fd << "'" << name_; } void ExpBitstring::write_to_stream(ostream&fd) diff --git a/vhdlpp/lexor_keyword.gperf b/vhdlpp/lexor_keyword.gperf index 7b739c80f..647798f27 100644 --- a/vhdlpp/lexor_keyword.gperf +++ b/vhdlpp/lexor_keyword.gperf @@ -96,6 +96,7 @@ rem, GN_KEYWORD_2008, K_rem report, GN_KEYWORD_2008, K_report restrict, GN_KEYWORD_2008, K_restrict return, GN_KEYWORD_2008, K_return +reverse_range, GN_KEYWORD_2008, K_reverse_range rol, GN_KEYWORD_2008, K_rol ror, GN_KEYWORD_2008, K_ror select, GN_KEYWORD_2008, K_select diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index f86c590e9..52943156e 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -363,7 +363,7 @@ static void import_ieee_use(ActiveScope*res, perm_string package, perm_string na const VTypePrimitive primitive_BOOLEAN(VTypePrimitive::BOOLEAN, true); const VTypePrimitive primitive_BIT(VTypePrimitive::BIT, true); -const VTypePrimitive primitive_INTEGER(VTypePrimitive::INTEGER, true); +const VTypePrimitive primitive_INTEGER(VTypePrimitive::INTEGER); const VTypePrimitive primitive_REAL(VTypePrimitive::REAL); const VTypePrimitive primitive_STDLOGIC(VTypePrimitive::STDLOGIC, true); const VTypePrimitive primitive_CHARACTER(VTypePrimitive::CHARACTER); diff --git a/vhdlpp/package.cc b/vhdlpp/package.cc index e1a6c7de3..9c0025f47 100644 --- a/vhdlpp/package.cc +++ b/vhdlpp/package.cc @@ -75,6 +75,10 @@ void Package::write_to_stream(ostream&fd) const continue; if (cur->first == "std_logic_vector") continue; + if (cur->first == "signed") + continue; + if (cur->first == "unsigned") + continue; fd << "type " << cur->first << " is "; cur->second->write_type_to_stream(fd); diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 26bfb0c86..7c37a7e0b 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -85,6 +85,10 @@ static ActiveScope*active_scope = new ActiveScope; static stack scope_stack; static Subprogram*active_sub = NULL; +// perm_strings for attributes +const static perm_string left_attr = perm_string::literal("left"); +const static perm_string right_attr = perm_string::literal("right"); + /* * When a scope boundary starts, call the push_scope function to push * a scope context. Preload this scope context with the contents of @@ -276,7 +280,7 @@ static void touchup_interface_for_functions(std::list*ports) %token K_package K_parameter K_port K_postponed K_procedure K_process %token K_property K_protected K_pure %token K_range K_record K_register K_reject K_release K_rem K_report -%token K_restrict K_restrict_guarantee K_return K_rol K_ror +%token K_restrict K_restrict_guarantee K_return K_reverse_range K_rol K_ror %token K_select K_sequence K_severity K_signal K_shared %token K_sla K_sll K_sra K_srl K_strong K_subtype %token K_then K_to K_transport K_type @@ -1904,6 +1908,34 @@ range { prange_t* tmp = new prange_t($1, $3, $2); $$ = tmp; } + | name '\'' K_range + { + prange_t*tmp = NULL; + ExpName*name = NULL; + if((name = dynamic_cast($1))) { + ExpAttribute*left = new ExpAttribute(name, left_attr); + ExpAttribute*right = new ExpAttribute(name, right_attr); + tmp = new prange_t(left, right, true); + tmp->set_auto_dir(); + } else { + errormsg(@1, "'range attribute can be used with named expressions only"); + } + $$ = tmp; + } + | name '\'' K_reverse_range + { + prange_t*tmp = NULL; + ExpName*name = NULL; + if((name = dynamic_cast($1))) { + ExpAttribute*left = new ExpAttribute(name, left_attr); + ExpAttribute*right = new ExpAttribute(name, right_attr); + tmp = new prange_t(left, right, false); + tmp->set_auto_dir(); + } else { + errormsg(@1, "'reverse_range attribute can be used with named expressions only"); + } + $$ = tmp; + } ; range_list diff --git a/vhdlpp/parse_types.h b/vhdlpp/parse_types.h index 2e517127f..625312762 100644 --- a/vhdlpp/parse_types.h +++ b/vhdlpp/parse_types.h @@ -71,7 +71,7 @@ class instant_list_t { class prange_t { public: prange_t(Expression* left, Expression* right, bool dir) - : left_(left), right_(right), direction_(dir) {} + : left_(left), right_(right), direction_(dir), auto_dir_(false) {} ~prange_t() { delete left_; delete right_; } void dump(ostream&out, int indent) const; @@ -79,12 +79,16 @@ class prange_t { inline Expression*lsb() { return direction_? right_: left_; } inline bool is_downto() const { return direction_; } + inline void set_auto_dir(bool enabled = true) { auto_dir_ = enabled; }; + inline bool is_auto_dir() const { return auto_dir_; } + inline Expression*expr_left() { return left_; } inline Expression*expr_right() { return right_; } private: Expression *left_, *right_; bool direction_; + bool auto_dir_; private: //not implemented prange_t(const prange_t&); diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index e3c0fab71..86a9a529c 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -212,24 +212,34 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, Architecture*arc) ivl_assert(*this, start_rc); ivl_assert(*this, finish_rc); - if (! range_->is_downto()) { + bool dir = range_->is_downto(); + + if (!dir) { int64_t tmp = start_val; start_val = finish_val; finish_val = tmp; } - if (range_->is_downto() && (start_val < finish_val)) { - out << "begin /* Degenerate loop at " << get_fileline() - << ": " << start_val - << " downto " << finish_val << " */ end" << endl; - return errors; + if (dir && (start_val < finish_val)) { + if(range_->is_auto_dir()) { + dir = false; + } else { + out << "begin /* Degenerate loop at " << get_fileline() + << ": " << start_val + << " downto " << finish_val << " */ end" << endl; + return errors; + } } - if (!range_->is_downto() && start_val > finish_val) { - out << "begin /* Degenerate loop at " << get_fileline() - << ": " << start_val - << " to " << finish_val << " */ end" << endl; - return errors; + else if (!dir && start_val > finish_val) { + if(range_->is_auto_dir()) { + dir = true; + } else { + out << "begin /* Degenerate loop at " << get_fileline() + << ": " << start_val + << " to " << finish_val << " */ end" << endl; + return errors; + } } perm_string scope_name = loop_name(); @@ -242,12 +252,12 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, Architecture*arc) out << "begin : " << scope_name << endl; out << "longint \\" << it_ << " ;" << endl; out << "for (\\" << it_ << " = " << start_val << " ; "; - if (range_->is_downto()) + if (dir) out << "\\" << it_ << " >= " << finish_val; else out << "\\" << it_ << " <= " << finish_val; out << "; \\" << it_ << " = \\" << it_; - if (range_->is_downto()) + if (dir) out << " - 1"; else out << " + 1"; diff --git a/vhdlpp/subprogram_emit.cc b/vhdlpp/subprogram_emit.cc index f3a2a428e..6f1b37508 100644 --- a/vhdlpp/subprogram_emit.cc +++ b/vhdlpp/subprogram_emit.cc @@ -70,7 +70,7 @@ int Subprogram::emit_package(ostream&fd) const if (statements_) { for (list::const_iterator cur = statements_->begin() ; cur != statements_->end() ; ++cur) { - errors += (*cur)->emit(fd, 0, 0); + errors += (*cur)->emit(fd, NULL, NULL); } } else { fd << " begin /* empty body */ end" << endl; diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index 2ccb999fb..580cf92b9 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -195,6 +195,7 @@ class VTypeArray : public VType { int elaborate(Entity*ent, Architecture*arc) const; void write_to_stream(std::ostream&fd) const; + void write_type_to_stream(std::ostream&fd) const; void show(std::ostream&) const; inline size_t dimensions() const { return ranges_.size(); }; @@ -312,7 +313,7 @@ class VTypeDef : public VType { inline const VType* peek_definition(void) const { return type_; } void write_to_stream(std::ostream&fd) const; - void write_type_to_stream(ostream&fd) const; + void write_type_to_stream(std::ostream&fd) const; int emit_typedef(std::ostream&out, typedef_context_t&ctx) const; int emit_def(std::ostream&out, perm_string name) const; diff --git a/vhdlpp/vtype_emit.cc b/vhdlpp/vtype_emit.cc index 9dc17b5f2..aa24dd362 100644 --- a/vhdlpp/vtype_emit.cc +++ b/vhdlpp/vtype_emit.cc @@ -146,7 +146,7 @@ int VTypePrimitive::emit_primitive_type(ostream&out) const out << "logic"; break; case INTEGER: - out << "bool[31:0]"; + out << "int"; break; case REAL: out << "real"; diff --git a/vhdlpp/vtype_stream.cc b/vhdlpp/vtype_stream.cc index 1392a6c50..b66428626 100644 --- a/vhdlpp/vtype_stream.cc +++ b/vhdlpp/vtype_stream.cc @@ -90,9 +90,40 @@ void VTypeArray::write_range_to_stream_(std::ostream&fd) const fd << ") "; } +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; + } + + fd << "array "; + + if (! ranges_.empty()) { + assert(ranges_.size() < 2); + if (ranges_[0].is_box()) { + fd << "(INTEGER range <>) "; + } else { + write_range_to_stream_(fd); + } + } + + fd << "of "; + + if(const VTypeDef*tdef = dynamic_cast(etype_)) { + tdef->write_to_stream(fd); + } else { + etype_->write_to_stream(fd); + } +} + void VTypeDef::write_type_to_stream(ostream&fd) const { - type_->write_to_stream(fd); + type_->write_type_to_stream(fd); } void VTypeDef::write_to_stream(ostream&fd) const diff --git a/vvp/parse.y b/vvp/parse.y index 69102570d..cc5c74eb8 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -808,6 +808,10 @@ statement symbols_net ';' { compile_netw($1, $3, $4, $6, $7, vpiLogicVar, true, $9.cnt, $9.vect); } + | T_LABEL K_NET_2S T_SYMBOL T_NUMBER ',' signed_t_number signed_t_number ',' + symbols_net ';' + { compile_netw($1, $3, $4, $6, $7, vpiIntVar, true, $9.cnt, $9.vect); } + | T_LABEL K_NET8 T_SYMBOL T_NUMBER ',' signed_t_number signed_t_number ',' symbols_net ';' { compile_netw($1, $3, $4, $6, $7, -vpiLogicVar, false, $9.cnt, $9.vect); }