From 1852c5ab9dddc2d614d6f4385b5532bc58dda00e Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 20 Feb 2015 17:27:31 +0100 Subject: [PATCH 01/13] Revert "vhdlpp: Support for accessing words in constant arrays." This reverts commit 9ca754b6db20030965b899bcbfa9a81c26bfce77. --- vhdlpp/expression_elaborate.cc | 76 +--------------------------------- 1 file changed, 1 insertion(+), 75 deletions(-) diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index a2cdbe3aa..19c79b591 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -922,87 +922,13 @@ const VType* ExpName::fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*)co return probe_type(ent, scope); } -int ExpName::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) +int ExpName::elaborate_expr(Entity*, ScopeBase*, const VType*ltype) { - const VType*type = NULL; - Expression*exp = NULL; - if (ltype) { ivl_assert(*this, ltype != 0); set_type(ltype); } - // Currently constant arrays of vectors are flattened to single one-dimensional - // localparams. If the user wants to access a particular word, then it is - // necessary to extract the adequate part of the localparam. - // e.g. - // declarations: - // == VHDL == - // type uns_array is array (natural range <>) of unsigned(7 downto 0); - // constant const_array : uns_array(2 downto 0) := - // (0 => "00110011", 1 => "101010101", 2=> "00001111"); - // == SystemVerilog == - // localparam const_array = { 8'b00110011, 8'b10101010, 8'b00001111 }; - // - // access: - // == VHDL == - // target_var := const_array(1); - // == SystemVerilog == - // target_var = const_array[15:8]; // <- indices adjusted to pick the word - - if(index_ && scope) { - if(!scope->find_constant(name_, type, exp)) - return 0; - - const VTypeArray*arr = dynamic_cast(type); - ivl_assert(*this, arr); // if there is an index, it should be an array, right? - - const VType*element = arr->element_type(); - const VTypeArray*arr_element = dynamic_cast(element); - if(!arr_element) { - // index adjustments are not necessary, it is not an array of vectors - return 0; - } - - ivl_assert(*this, arr_element->dimensions() == 1); - if(arr_element->dimensions() != 1) { - cerr << get_fileline() << ": Sorry, only one-dimensional constant arrays are handled." << endl; - return 1; - } - - int64_t start_val; - bool start_rc = arr_element->dimension(0).msb()->evaluate(ent, scope, start_val); - - int64_t finish_val; - bool finish_rc = arr_element->dimension(0).lsb()->evaluate(ent, scope, finish_val); - - if(!start_rc || !finish_rc) { - cerr << get_fileline() << ": Could not evaluate the word size." << endl; - return 1; - } - - int word_size = abs(start_val - finish_val) + 1; - - ExpInteger*size = new ExpInteger(word_size); - Expression*new_index, *new_lsb; - - // new indices = [index_ * word_size + word_size : lsb_ * word_size] - if(lsb_) { - ExpArithmetic*tmp = new ExpArithmetic(ExpArithmetic::MULT, index_->clone(), size->clone()); - new_index = new ExpArithmetic(ExpArithmetic::PLUS, tmp, size->clone()); - new_lsb = new ExpArithmetic(ExpArithmetic::MULT, lsb_->clone(), size->clone()); - } else { - new_lsb = new ExpArithmetic(ExpArithmetic::MULT, index_->clone(), size->clone()); - new_index = new ExpArithmetic(ExpArithmetic::PLUS, new_lsb->clone(), size->clone()); - } - delete index_; - delete lsb_; - delete size; - - index_ = new_index; - lsb_ = new_lsb; - } - return 0; } From a42b056b24a3174a177ea78f9ffa6f9d941a3bf7 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 20 Feb 2015 18:37:22 +0100 Subject: [PATCH 02/13] vhdlpp: Alternative way of accessing constant arrays of vectors. --- vhdlpp/expression.h | 6 ++++ vhdlpp/expression_emit.cc | 59 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index 422f1167c..92b48f605 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -649,6 +649,12 @@ class ExpName : public Expression { int emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope); + // Constant arrays of vectors are flattened into a single localparam, + // therefore indices of such localparam point to a bit, not a word. + // The following workaround expands expressions to a concatenation of + // bits making the requested word. + bool emit_const_array_workaround_(ostream&out, Entity*ent, ScopeBase*scope) const; + private: std::auto_ptr prefix_; perm_string name_; diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 5689e29c1..5975cbed5 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -715,6 +715,9 @@ int ExpName::emit(ostream&out, Entity*ent, ScopeBase*scope) errors += prefix_->emit_as_prefix_(out, ent, scope); } + if(index_ && emit_const_array_workaround_(out, ent, scope)) + return errors; + const GenerateStatement*gs = 0; Architecture*arc = dynamic_cast(scope); if (arc && (gs = arc->probe_genvar_emit(name_))) @@ -736,6 +739,62 @@ int ExpName::emit(ostream&out, Entity*ent, ScopeBase*scope) return errors; } +bool ExpName::emit_const_array_workaround_(ostream&out, Entity*ent, ScopeBase*scope) const +{ + const VType*type = NULL; + Expression*exp = NULL; + + if(!scope) + return false; + + if(!scope->find_constant(name_, type, exp)) + return false; + + const VTypeArray*arr = dynamic_cast(type); + ivl_assert(*this, arr); // if there is an index, it should be an array, right? + + const VType*element = arr->element_type(); + const VTypeArray*arr_element = dynamic_cast(element); + if(!arr_element) { + // index adjustments are not necessary, it is not an array of vectors + return false; + } + + ivl_assert(*this, arr_element->dimensions() == 1); + if(arr_element->dimensions() != 1) { + cerr << get_fileline() << ": Sorry, only one-dimensional constant arrays are handled." << endl; + return false; + } + + int64_t start_val; + bool start_rc = arr_element->dimension(0).msb()->evaluate(ent, scope, start_val); + + int64_t finish_val; + bool finish_rc = arr_element->dimension(0).lsb()->evaluate(ent, scope, finish_val); + + if(!start_rc || !finish_rc) { + cerr << get_fileline() << ": Could not evaluate the word size." << endl; + return false; + } + + int word_size = abs(start_val - finish_val) + 1; + if(start_val > finish_val) + swap(start_val, finish_val); + + out << "{"; + for(int i = finish_val; i >= start_val; --i) { + if(i != finish_val) + out << ","; + + out << "\\" << name_ << " [" << word_size << "*"; + index_->emit(out, ent, scope); + out << "+" << i << "]"; + } + out << "}"; + + return true; +} + bool ExpName::is_primary(void) const { return true; From 4b0d2206718db04d3b4a0642d6f8adc966cd4198 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 26 Feb 2015 13:27:47 +0100 Subject: [PATCH 03/13] vhdlpp: get_width() for VType. --- vhdlpp/vtype.cc | 61 +++++++++++++++++++++++++++++++++++++++++++++++++ vhdlpp/vtype.h | 11 +++++++++ 2 files changed, 72 insertions(+) diff --git a/vhdlpp/vtype.cc b/vhdlpp/vtype.cc index 9acfcacee..37f89a6fe 100644 --- a/vhdlpp/vtype.cc +++ b/vhdlpp/vtype.cc @@ -79,6 +79,26 @@ void VTypePrimitive::show(ostream&out) const } } +int VTypePrimitive::get_width() const +{ + switch(type_) { + case BOOLEAN: + case BIT: + case STDLOGIC: + case REAL: + return 1; + + case INTEGER: + case NATURAL: + return 32; + + case CHARACTER: + return 8; + } + + return -1; +} + VTypeArray::range_t*VTypeArray::range_t::clone() const { return new VTypeArray::range_t(safe_clone(msb_), safe_clone(lsb_), direction_); @@ -176,6 +196,30 @@ void VTypeArray::show(ostream&out) const out << ""; } +int VTypeArray::get_width() const +{ + int64_t size = 1; + + for(vector::const_iterator it = ranges_.begin(); + it != ranges_.end(); ++it) { + const VTypeArray::range_t&dim = *it; + int64_t msb_val, lsb_val; + + if(dim.is_box()) + return false; + + if(!dim.msb()->evaluate(NULL, msb_val)) + return -1; + + if(!dim.lsb()->evaluate(NULL, lsb_val)) + return -1; + + size *= 1 + labs(msb_val - lsb_val); + } + + return etype_->get_width() * size; +} + bool VTypeArray::is_unbounded() const { for(std::vector::const_iterator it = ranges_.begin(); it != ranges_.end(); ++it) @@ -281,6 +325,23 @@ void VTypeRecord::show(ostream&out) const write_to_stream(out); } +int VTypeRecord::get_width() const +{ + int width = 0; + + for(vector::const_iterator it = elements_.begin(); + it != elements_.end(); ++it) { + int w = (*it)->peek_type()->get_width(); + + if(w < 0) + return -1; + + width += w; + } + + return width; +} + const VTypeRecord::element_t* VTypeRecord::element_by_name(perm_string name, int*index) const { for (vector::const_iterator cur = elements_.begin() diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index c5cdff9a4..7e5ed6778 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -66,6 +66,7 @@ class VType { // of this type to the designated stream. This is used for // writing parsed types to library files. virtual void write_to_stream(std::ostream&fd) const; + // This is like the above, but is the root function called // directly after the "type is..." when writing type // definitions. Most types accept the default definition of this. @@ -100,6 +101,10 @@ class VType { // typedefs (i.e. not ones defined by the user). perm_string get_generic_typename() const; + // Returns the type width in bits or negative number if it is impossible + // to evaluate. + virtual int get_width() const { return -1; } + private: friend struct decl_t; // This virtual method is called to emit the declaration. This @@ -161,6 +166,7 @@ class VTypePrimitive : public VType { void write_to_stream(std::ostream&fd) const; void show(std::ostream&) const; + int get_width() const; type_t type() const { return type_; } @@ -221,6 +227,7 @@ class VTypeArray : public VType { void write_to_stream(std::ostream&fd) const; void write_type_to_stream(std::ostream&fd) const; void show(std::ostream&) const; + int get_width() const; inline size_t dimensions() const { return ranges_.size(); }; const range_t&dimension(size_t idx) const @@ -294,6 +301,8 @@ class VTypeEnum : public VType { void write_to_stream(std::ostream&fd) const; void show(std::ostream&) const; + int get_width() const { return 32; } + int emit_def(std::ostream&out, perm_string name) const; // Checks if the name is stored in the enum. @@ -332,6 +341,7 @@ class VTypeRecord : public VType { void write_to_stream(std::ostream&fd) const; void show(std::ostream&) const; + int get_width() const; int emit_def(std::ostream&out, perm_string name) const; bool can_be_packed() const { return true; } @@ -362,6 +372,7 @@ class VTypeDef : public VType { void write_to_stream(std::ostream&fd) const; void write_type_to_stream(std::ostream&fd) const; + int get_width() const { return type_->get_width(); } int emit_typedef(std::ostream&out, typedef_context_t&ctx) const; int emit_def(std::ostream&out, perm_string name) const; From afbda099fbd0e83213dd41bd823c5e4115290037 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 24 Feb 2015 16:06:55 +0100 Subject: [PATCH 04/13] vhdlpp: Workaround to handle constant arrays of vectors & records. --- vhdlpp/expression.cc | 29 +++++-- vhdlpp/expression.h | 38 +++++++-- vhdlpp/expression_emit.cc | 146 +++++++++++++++++++++++++--------- vhdlpp/expression_evaluate.cc | 3 + vhdlpp/parse.y | 7 +- vhdlpp/vtype.cc | 4 +- vhdlpp/vtype.h | 1 + 7 files changed, 172 insertions(+), 56 deletions(-) diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index 42991461d..04775f13d 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -1,6 +1,6 @@ /* * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) - * Copyright CERN 2012-2014 / Stephen Williams (steve@icarus.com), + * Copyright CERN 2012-2015 / Stephen Williams (steve@icarus.com), * Maciej Suminski (maciej.suminski@cern.ch) * * This source code is free software; you can redistribute it @@ -450,11 +450,6 @@ ExpName::~ExpName() delete index_; } -const char* ExpName::name() const -{ - return name_; -} - bool ExpName::symbolic_compare(const Expression*that) const { const ExpName*that_name = dynamic_cast (that); @@ -485,6 +480,28 @@ void ExpName::set_range(Expression*msb, Expression*lsb) lsb_ = lsb; } +int ExpName::index_t::emit(ostream&out, Entity*ent, ScopeBase*scope) +{ + int errors = 0; + + out << "("; + + if(idx_ && size_) { + errors += idx_->emit(out, ent, scope); + out << "*"; + errors += size_->emit(out, ent, scope); + } + + if(offset_) { + if(idx_ && size_) + out << "+"; + errors += offset_->emit(out, ent, scope); + } + + out << ")"; + return errors; +} + 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 92b48f605..831f41a60 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -2,7 +2,7 @@ #define IVL_expression_H /* * Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com) - * Copyright CERN 2014 / Stephen Williams (steve@icarus.com), + * Copyright CERN 2015 / Stephen Williams (steve@icarus.com), * Maciej Suminski (maciej.suminski@cern.ch) * * This source code is free software; you can redistribute it @@ -105,7 +105,6 @@ class Expression : public LineInfo { virtual bool evaluate(ScopeBase*scope, int64_t&val) const; virtual bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; - // The symbolic compare returns true if the two expressions // are equal without actually calculating the value. virtual bool symbolic_compare(const Expression*that) const; @@ -635,12 +634,25 @@ class ExpName : public Expression { bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; bool symbolic_compare(const Expression*that) const; void dump(ostream&out, int indent = 0) const; - const char* name() const; + inline const char* name() const { return name_; } inline const perm_string& peek_name() const { return name_; } void set_range(Expression*msb, Expression*lsb); private: + class index_t { + public: + index_t(Expression*idx, Expression*size, Expression*offset = NULL) : + idx_(idx), size_(size), offset_(offset) {} + + int emit(ostream&out, Entity*ent, ScopeBase*scope); + + private: + Expression*idx_; + Expression*size_; + Expression*offset_; + }; + const VType* elaborate_adjust_type_with_range_(Entity*ent, ScopeBase*scope, const VType*type); int elaborate_lval_(Entity*ent, ScopeBase*scope, bool, ExpName*suffix); @@ -649,11 +661,21 @@ class ExpName : public Expression { int emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope); - // Constant arrays of vectors are flattened into a single localparam, - // therefore indices of such localparam point to a bit, not a word. - // The following workaround expands expressions to a concatenation of - // bits making the requested word. - bool emit_const_array_workaround_(ostream&out, Entity*ent, ScopeBase*scope) const; + // There are some workarounds required for constant arrays/records, as + // they are currently emitted as flat localparams (without any type + // information). The following workarounds adjust the access indices + // to select appropriate parts of the localparam. + bool try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope, + list&indices, int&data_size); + + bool check_const_array_workaround_(const VTypeArray*arr, list&indices, + int&data_size) const; + + bool check_const_record_workaround_(const VTypeRecord*rec, list&indices, + int&data_size) const; + + int emit_workaround_(ostream&out, Entity*ent, ScopeBase*scope, + const list&indices, int field_size); private: std::auto_ptr prefix_; diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 5975cbed5..49f60446f 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -1,6 +1,7 @@ /* * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) - * Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com) + * Copyright CERN 2012-2015 / Stephen Williams (steve@icarus.com) + * 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 @@ -710,14 +711,18 @@ int ExpName::emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope) int ExpName::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; + int field_size = 0; + list indices; + + if(try_workarounds_(out, ent, scope, indices, field_size)) { + emit_workaround_(out, ent, scope, indices, field_size); + return 0; + } if (prefix_.get()) { errors += prefix_->emit_as_prefix_(out, ent, scope); } - if(index_ && emit_const_array_workaround_(out, ent, scope)) - return errors; - const GenerateStatement*gs = 0; Architecture*arc = dynamic_cast(scope); if (arc && (gs = arc->probe_genvar_emit(name_))) @@ -739,60 +744,123 @@ int ExpName::emit(ostream&out, Entity*ent, ScopeBase*scope) return errors; } -bool ExpName::emit_const_array_workaround_(ostream&out, Entity*ent, ScopeBase*scope) const +bool ExpName::try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope, + list& indices, int& data_size) { - const VType*type = NULL; Expression*exp = NULL; + bool wrkand_required = false; + const VType*type = NULL; if(!scope) return false; - if(!scope->find_constant(name_, type, exp)) - return false; + if(prefix_.get()) + prefix_->try_workarounds_(out, ent, scope, indices, data_size); - const VTypeArray*arr = dynamic_cast(type); - ivl_assert(*this, arr); // if there is an index, it should be an array, right? + if(index_ && !lsb_ && scope->find_constant(name_, type, exp)) { + while(const VTypeDef*type_def = dynamic_cast(type)) { + type = type_def->peek_definition(); + } + const VTypeArray*arr = dynamic_cast(type); + assert(arr); + wrkand_required |= check_const_array_workaround_(arr, indices, data_size); + } + + if(prefix_.get() && scope->find_constant(prefix_->name_, type, exp)) { + // Handle the case of array of records + if(prefix_->index_) { + const VTypeArray*arr = dynamic_cast(type); + assert(arr); + type = arr->element_type(); + data_size = type->get_width(); + } + + while(const VTypeDef*type_def = dynamic_cast(type)) { + type = type_def->peek_definition(); + } + + const VTypeRecord*rec = dynamic_cast(type); + assert(rec); + + wrkand_required |= check_const_record_workaround_(rec, indices, data_size); + } + + return wrkand_required; +} + +bool ExpName::check_const_array_workaround_(const VTypeArray*arr, + list&indices, int&data_size) const +{ const VType*element = arr->element_type(); - const VTypeArray*arr_element = dynamic_cast(element); - if(!arr_element) { - // index adjustments are not necessary, it is not an array of vectors - return false; + data_size = element->get_width(); + indices.push_back(new index_t(index_, new ExpInteger(data_size))); + return true; +} + +bool ExpName::check_const_record_workaround_(const VTypeRecord*rec, + list&indices, int&data_size) const +{ + int tmp_offset = 0; + const vector& elements = rec->get_elements(); + + for(vector::const_reverse_iterator it = elements.rbegin(); + it != elements.rend(); ++it) { + VTypeRecord::element_t* el = (*it); + + if(el->peek_name() == name_) { + const VType*type = el->peek_type(); + + int tmp_field = type->get_width(); + if(tmp_field < 0) + return false; + + data_size = tmp_field; + indices.push_back(new index_t(NULL, NULL, new ExpInteger(tmp_offset))); + + if(index_) { + const VTypeArray*arr = dynamic_cast(type); + assert(arr); + return check_const_array_workaround_(arr, indices, data_size); + } + + return true; + } + + int w = el->peek_type()->get_width(); + + if(w < 0) + return false; + + tmp_offset += w; } - ivl_assert(*this, arr_element->dimensions() == 1); - if(arr_element->dimensions() != 1) { - cerr << get_fileline() << ": Sorry, only one-dimensional constant arrays are handled." << endl; - return false; - } + return false; +} - int64_t start_val; - bool start_rc = arr_element->dimension(0).msb()->evaluate(ent, scope, start_val); - - int64_t finish_val; - bool finish_rc = arr_element->dimension(0).lsb()->evaluate(ent, scope, finish_val); - - if(!start_rc || !finish_rc) { - cerr << get_fileline() << ": Could not evaluate the word size." << endl; - return false; - } - - int word_size = abs(start_val - finish_val) + 1; - if(start_val > finish_val) - swap(start_val, finish_val); +int ExpName::emit_workaround_(ostream&out, Entity*ent, ScopeBase*scope, + const list& indices, int field_size) +{ + int errors = 0; out << "{"; - for(int i = finish_val; i >= start_val; --i) { - if(i != finish_val) + for(int i = field_size - 1; i >= 0; --i) { + if(i != field_size - 1) out << ","; - out << "\\" << name_ << " [" << word_size << "*"; - index_->emit(out, ent, scope); - out << "+" << i << "]"; + out << "\\" << (prefix_.get() ? prefix_->name_ : name_) << " ["; + + for(list::const_iterator it = indices.begin(); + it != indices.end(); ++it) { + errors += (*it)->emit(out, ent, scope); + out << " + "; + } + + out << i << "]"; } out << "}"; - return true; + return errors; } bool ExpName::is_primary(void) const diff --git a/vhdlpp/expression_evaluate.cc b/vhdlpp/expression_evaluate.cc index 8280c08e7..b81b6a30d 100644 --- a/vhdlpp/expression_evaluate.cc +++ b/vhdlpp/expression_evaluate.cc @@ -191,6 +191,9 @@ bool ExpName::evaluate(ScopeBase*scope, int64_t&val) const return false; } + if(!scope) + return false; + bool rc = scope->find_constant(name_, type, exp); if (rc == false) return false; diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index f824f3bad..48235e0a1 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -1601,11 +1601,16 @@ name /* IEEE 1076-2008 P8.1 */ delete[]$1; $$ = tmp; } - | selected_name '(' range ')' + | selected_name '(' range ')' { ExpName*tmp = dynamic_cast ($1); tmp->set_range($3->msb(), $3->lsb()); $$ = tmp; } + | selected_name '(' expression ')' + { ExpName*tmp = dynamic_cast ($1); + tmp->set_range($3, NULL); + $$ = tmp; + } ; /* Handle name lists as lists of expressions. */ diff --git a/vhdlpp/vtype.cc b/vhdlpp/vtype.cc index 37f89a6fe..f91d994b2 100644 --- a/vhdlpp/vtype.cc +++ b/vhdlpp/vtype.cc @@ -206,7 +206,7 @@ int VTypeArray::get_width() const int64_t msb_val, lsb_val; if(dim.is_box()) - return false; + return -1; if(!dim.msb()->evaluate(NULL, msb_val)) return -1; @@ -217,7 +217,7 @@ int VTypeArray::get_width() const size *= 1 + labs(msb_val - lsb_val); } - return etype_->get_width() * size; + return element_type()->get_width() * size; } bool VTypeArray::is_unbounded() const { diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index 7e5ed6778..1819ea31c 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -346,6 +346,7 @@ class VTypeRecord : public VType { bool can_be_packed() const { return true; } const element_t* element_by_name(perm_string name, int*index = NULL) const; + inline const std::vector get_elements() const { return elements_; } private: std::vector elements_; From 9128eb67b98f3a99a4181727f21e19a317091d0f Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 2 Mar 2015 14:09:30 +0100 Subject: [PATCH 05/13] vhdlpp: Evaluates attributes if possible. --- vhdlpp/expression_emit.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 49f60446f..61f241490 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -307,6 +307,13 @@ int ExpAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; + // Try to evaluate first + int64_t val; + if(evaluate(scope, val)) { + out << val; + return 0; + } + if (name_ == "event") { out << "$ivlh_attribute_event("; errors += base_->emit(out, ent, scope); From e33b8b4ddeeec00cf64dcb0f9ddff12cc68d9208 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 2 Mar 2015 14:33:26 +0100 Subject: [PATCH 06/13] vhdlpp: VType::get_width() uses information from Scope to determine the type width. --- vhdlpp/expression.h | 8 ++++---- vhdlpp/expression_emit.cc | 21 ++++++++++++--------- vhdlpp/expression_evaluate.cc | 19 +++++-------------- vhdlpp/vtype.cc | 15 +++++++-------- vhdlpp/vtype.h | 12 ++++++------ 5 files changed, 34 insertions(+), 41 deletions(-) diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index 831f41a60..dd1ae6783 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -668,11 +668,11 @@ class ExpName : public Expression { bool try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope, list&indices, int&data_size); - bool check_const_array_workaround_(const VTypeArray*arr, list&indices, - int&data_size) const; + bool check_const_array_workaround_(const VTypeArray*arr, ScopeBase*scope, + list&indices, int&data_size) const; - bool check_const_record_workaround_(const VTypeRecord*rec, list&indices, - int&data_size) const; + bool check_const_record_workaround_(const VTypeRecord*rec, ScopeBase*scope, + list&indices, int&data_size) const; int emit_workaround_(ostream&out, Entity*ent, ScopeBase*scope, const list&indices, int field_size); diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 61f241490..7dee9ee47 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -771,7 +771,7 @@ bool ExpName::try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeArray*arr = dynamic_cast(type); assert(arr); - wrkand_required |= check_const_array_workaround_(arr, indices, data_size); + wrkand_required |= check_const_array_workaround_(arr, scope, indices, data_size); } if(prefix_.get() && scope->find_constant(prefix_->name_, type, exp)) { @@ -780,7 +780,7 @@ bool ExpName::try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeArray*arr = dynamic_cast(type); assert(arr); type = arr->element_type(); - data_size = type->get_width(); + data_size = type->get_width(scope); } while(const VTypeDef*type_def = dynamic_cast(type)) { @@ -790,23 +790,26 @@ bool ExpName::try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeRecord*rec = dynamic_cast(type); assert(rec); - wrkand_required |= check_const_record_workaround_(rec, indices, data_size); + wrkand_required |= check_const_record_workaround_(rec, scope, indices, data_size); } return wrkand_required; } bool ExpName::check_const_array_workaround_(const VTypeArray*arr, - list&indices, int&data_size) const + ScopeBase*scope, list&indices, int&data_size) const { const VType*element = arr->element_type(); - data_size = element->get_width(); + data_size = element->get_width(scope); + if(data_size < 0) + return false; indices.push_back(new index_t(index_, new ExpInteger(data_size))); + return true; } bool ExpName::check_const_record_workaround_(const VTypeRecord*rec, - list&indices, int&data_size) const + ScopeBase*scope, list&indices, int&data_size) const { int tmp_offset = 0; const vector& elements = rec->get_elements(); @@ -818,7 +821,7 @@ bool ExpName::check_const_record_workaround_(const VTypeRecord*rec, if(el->peek_name() == name_) { const VType*type = el->peek_type(); - int tmp_field = type->get_width(); + int tmp_field = type->get_width(scope); if(tmp_field < 0) return false; @@ -828,13 +831,13 @@ bool ExpName::check_const_record_workaround_(const VTypeRecord*rec, if(index_) { const VTypeArray*arr = dynamic_cast(type); assert(arr); - return check_const_array_workaround_(arr, indices, data_size); + return check_const_array_workaround_(arr, scope, indices, data_size); } return true; } - int w = el->peek_type()->get_width(); + int w = el->peek_type()->get_width(scope); if(w < 0) return false; diff --git a/vhdlpp/expression_evaluate.cc b/vhdlpp/expression_evaluate.cc index b81b6a30d..2d498c020 100644 --- a/vhdlpp/expression_evaluate.cc +++ b/vhdlpp/expression_evaluate.cc @@ -33,7 +33,6 @@ bool Expression::evaluate(Entity*, ScopeBase*scope, int64_t&val) const return evaluate(scope, val); } - bool ExpArithmetic::evaluate(ScopeBase*scope, int64_t&val) const { int64_t val1, val2; @@ -113,20 +112,12 @@ bool ExpAttribute::evaluate(ScopeBase*scope, int64_t&val) const } if(name_ == "length") { - int64_t size = 1; - for (size_t idx = 0 ; idx < arr->dimensions() ; idx += 1) { - const VTypeArray::range_t&dim = arr->dimension(idx); - int64_t msb_val, lsb_val; + int64_t size = arr->get_width(scope); - if(dim.is_box()) - return false; - - dim.msb()->evaluate(scope, msb_val); - dim.lsb()->evaluate(scope, lsb_val); - - size *= 1 + labs(msb_val - lsb_val); - } - val = size; + if(size > 0) + val = size; + else + return false; } else if(name_ == "left") { arr->dimension(0).msb()->evaluate(scope, val); } else if(name_ == "right") { diff --git a/vhdlpp/vtype.cc b/vhdlpp/vtype.cc index f91d994b2..7a6581148 100644 --- a/vhdlpp/vtype.cc +++ b/vhdlpp/vtype.cc @@ -79,13 +79,12 @@ void VTypePrimitive::show(ostream&out) const } } -int VTypePrimitive::get_width() const +int VTypePrimitive::get_width(ScopeBase*) const { switch(type_) { case BOOLEAN: case BIT: case STDLOGIC: - case REAL: return 1; case INTEGER: @@ -196,7 +195,7 @@ void VTypeArray::show(ostream&out) const out << ""; } -int VTypeArray::get_width() const +int VTypeArray::get_width(ScopeBase*scope) const { int64_t size = 1; @@ -208,16 +207,16 @@ int VTypeArray::get_width() const if(dim.is_box()) return -1; - if(!dim.msb()->evaluate(NULL, msb_val)) + if(!dim.msb()->evaluate(scope, msb_val)) return -1; - if(!dim.lsb()->evaluate(NULL, lsb_val)) + if(!dim.lsb()->evaluate(scope, lsb_val)) return -1; size *= 1 + labs(msb_val - lsb_val); } - return element_type()->get_width() * size; + return element_type()->get_width(scope) * size; } bool VTypeArray::is_unbounded() const { @@ -325,13 +324,13 @@ void VTypeRecord::show(ostream&out) const write_to_stream(out); } -int VTypeRecord::get_width() const +int VTypeRecord::get_width(ScopeBase*scope) const { int width = 0; for(vector::const_iterator it = elements_.begin(); it != elements_.end(); ++it) { - int w = (*it)->peek_type()->get_width(); + int w = (*it)->peek_type()->get_width(scope); if(w < 0) return -1; diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index 1819ea31c..47683b637 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -103,7 +103,7 @@ class VType { // Returns the type width in bits or negative number if it is impossible // to evaluate. - virtual int get_width() const { return -1; } + virtual int get_width(ScopeBase*) const { return -1; } private: friend struct decl_t; @@ -166,7 +166,7 @@ class VTypePrimitive : public VType { void write_to_stream(std::ostream&fd) const; void show(std::ostream&) const; - int get_width() const; + int get_width(ScopeBase*scope) const; type_t type() const { return type_; } @@ -227,7 +227,7 @@ class VTypeArray : public VType { void write_to_stream(std::ostream&fd) const; void write_type_to_stream(std::ostream&fd) const; void show(std::ostream&) const; - int get_width() const; + int get_width(ScopeBase*scope) const; inline size_t dimensions() const { return ranges_.size(); }; const range_t&dimension(size_t idx) const @@ -301,7 +301,7 @@ class VTypeEnum : public VType { void write_to_stream(std::ostream&fd) const; void show(std::ostream&) const; - int get_width() const { return 32; } + int get_width(ScopeBase*) const { return 32; } int emit_def(std::ostream&out, perm_string name) const; @@ -341,7 +341,7 @@ class VTypeRecord : public VType { void write_to_stream(std::ostream&fd) const; void show(std::ostream&) const; - int get_width() const; + int get_width(ScopeBase*scope) const; int emit_def(std::ostream&out, perm_string name) const; bool can_be_packed() const { return true; } @@ -373,7 +373,7 @@ class VTypeDef : public VType { void write_to_stream(std::ostream&fd) const; void write_type_to_stream(std::ostream&fd) const; - int get_width() const { return type_->get_width(); } + int get_width(ScopeBase*scope) const { return type_->get_width(scope); } int emit_typedef(std::ostream&out, typedef_context_t&ctx) const; int emit_def(std::ostream&out, perm_string name) const; From 1de3fb162563a46dba0ca95b754ba98e692e6929 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 2 Mar 2015 16:35:51 +0100 Subject: [PATCH 07/13] vhdlpp: "resize" function. --- vhdlpp/expression_emit.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 7dee9ee47..bb88ddfe5 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -560,12 +560,13 @@ int ExpFunc::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; - // SystemVerilog takes care of signs, depending on the lvalue - if (name_ == "to_integer" && argv_.size()==1) { + // SystemVerilog takes care of sign & width, depending on the lvalue type + if ((name_ == "to_integer" && argv_.size() == 1) || + (name_ == "resize" && argv_.size() == 2)) { errors += argv_[0]->emit(out, ent, scope); } - else if (name_ == "unsigned" && argv_.size()==1) { + else 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 From d406545331a91ebb35cf7d671d7ec49a280ed62f Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 5 Mar 2015 16:12:40 +0100 Subject: [PATCH 08/13] vpi: $ivlh_{rising,falling}_edge functions. --- vpi/vhdl_sys.sft | 2 ++ vpi/vhdl_table.c | 65 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/vpi/vhdl_sys.sft b/vpi/vhdl_sys.sft index 7e9c7aaac..d0d452212 100644 --- a/vpi/vhdl_sys.sft +++ b/vpi/vhdl_sys.sft @@ -1 +1,3 @@ $ivlh_attribute_event vpiSysFuncSized 1 unsigned +$ivlh_rising_edge vpiSysFuncSized 1 unsigned +$ivlh_falling_edge vpiSysFuncSized 1 unsigned diff --git a/vpi/vhdl_table.c b/vpi/vhdl_table.c index 657ffd76b..a6dcac300 100644 --- a/vpi/vhdl_table.c +++ b/vpi/vhdl_table.c @@ -28,14 +28,25 @@ * operand, and noting the time. If the $ivlh_attribute_event is * called at the same simulation time as a value-change, then the * function returns logic true. Otherwise it returns false. + * + * $ivlh_{rising,falling}_edge implement the VHDL rising_edge() and + * falling_edge() system functions. */ struct monitor_data { struct t_vpi_time last_event; + struct t_vpi_value last_value; }; static struct monitor_data **mdata = 0; static unsigned mdata_count = 0; +typedef enum { EVENT = 0, RISING_EDGE = 1, FALLING_EDGE = 2 } event_type_t; +static const char* func_names[] = { + "$ivlh_attribute_event", + "$ivlh_rising_edge", + "$ivlh_falling_edge" +}; + /* To keep valgrind happy free the allocated memory. */ static PLI_INT32 cleanup_mdata(p_cb_data cause) { @@ -59,26 +70,30 @@ static PLI_INT32 monitor_events(struct t_cb_data*cb) assert(cb->time); assert(cb->time->type == vpiSimTime); + mon->last_event = *(cb->time); + mon->last_value = *(cb->value); return 0; } -static PLI_INT32 ivlh_attribute_event_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) +static PLI_INT32 ivlh_attribute_event_compiletf(ICARUS_VPI_CONST PLI_BYTE8*data) { + event_type_t type = (event_type_t) data; vpiHandle sys = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, sys); vpiHandle arg; struct monitor_data*mon; struct t_cb_data cb; struct t_vpi_time tb; + struct t_vpi_value vb; /* Check that there are arguments. */ if (argv == 0) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys), (int)vpi_get(vpiLineNo, sys)); vpi_printf("(compiler error) %s requires a single argument.\n", - name); + func_names[type]); vpi_control(vpiFinish, 1); return 0; } @@ -96,11 +111,12 @@ static PLI_INT32 ivlh_attribute_event_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) mdata[mdata_count-1] = mon; tb.type = vpiSimTime; + vb.format = vpiScalarVal; cb.reason = cbValueChange; cb.cb_rtn = monitor_events; cb.obj = arg; cb.time = &tb; - cb.value = 0; + cb.value = &vb; cb.user_data = (char*) (mon); vpi_register_cb(&cb); vpi_put_userdata(sys, mon); @@ -111,7 +127,7 @@ static PLI_INT32 ivlh_attribute_event_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys), (int)vpi_get(vpiLineNo, sys)); vpi_printf("(compiler error) %s only takes a single argument.\n", - name); + func_names[type]); vpi_free_object(argv); vpi_control(vpiFinish, 1); } @@ -119,14 +135,13 @@ static PLI_INT32 ivlh_attribute_event_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } -static PLI_INT32 ivlh_attribute_event_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) +static PLI_INT32 ivlh_attribute_event_calltf(ICARUS_VPI_CONST PLI_BYTE8*data) { + event_type_t type = (event_type_t) data; vpiHandle sys = vpi_handle(vpiSysTfCall, 0); struct t_vpi_value rval; struct monitor_data*mon; - (void) name; /* Parameter is not used. */ - rval.format = vpiScalarVal; mon = (struct monitor_data*) (vpi_get_userdata(sys)); @@ -140,10 +155,18 @@ static PLI_INT32 ivlh_attribute_event_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) vpi_get_time(0, &tnow); rval.value.scalar = vpi1; + + // Detect if there was any change 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) + rval.value.scalar = vpi0; + else if (type == FALLING_EDGE && mon->last_value.value.scalar == vpi1) + rval.value.scalar = vpi0; } vpi_put_value(sys, &rval, 0, vpiNoDelay); @@ -151,9 +174,9 @@ static PLI_INT32 ivlh_attribute_event_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } -static PLI_INT32 ivlh_attribute_event_sizetf(ICARUS_VPI_CONST PLI_BYTE8*name) +static PLI_INT32 ivlh_attribute_event_sizetf(ICARUS_VPI_CONST PLI_BYTE8*type) { - (void) name; /* Parameter is not used. */ + (void) type; /* Parameter is not used. */ return 1; } @@ -168,8 +191,28 @@ static void vhdl_register(void) tf_data.calltf = ivlh_attribute_event_calltf; tf_data.compiletf = ivlh_attribute_event_compiletf; tf_data.sizetf = ivlh_attribute_event_sizetf; - tf_data.tfname = "$ivlh_attribute_event"; - tf_data.user_data = (PLI_BYTE8 *) "$ivlh_attribute_event"; + tf_data.tfname = func_names[EVENT]; + tf_data.user_data = (PLI_BYTE8*) EVENT; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); + + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiSizedFunc; + tf_data.calltf = ivlh_attribute_event_calltf; + tf_data.compiletf = ivlh_attribute_event_compiletf; + tf_data.sizetf = ivlh_attribute_event_sizetf; + tf_data.tfname = func_names[RISING_EDGE]; + tf_data.user_data = (PLI_BYTE8*) RISING_EDGE; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); + + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiSizedFunc; + tf_data.calltf = ivlh_attribute_event_calltf; + tf_data.compiletf = ivlh_attribute_event_compiletf; + tf_data.sizetf = ivlh_attribute_event_sizetf; + tf_data.tfname = func_names[FALLING_EDGE]; + tf_data.user_data = (PLI_BYTE8*) FALLING_EDGE; res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); From 099bb427bce14d369418ce24e169320dd52ba368 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 6 Mar 2015 15:22:47 +0100 Subject: [PATCH 09/13] vhdlpp: ComponentBase::write_to_stream() saves generics. --- vhdlpp/entity_stream.cc | 74 ++++++++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 23 deletions(-) diff --git a/vhdlpp/entity_stream.cc b/vhdlpp/entity_stream.cc index 5b04938ee..cd1e67334 100644 --- a/vhdlpp/entity_stream.cc +++ b/vhdlpp/entity_stream.cc @@ -18,40 +18,68 @@ */ # include "entity.h" +# include "expression.h" using namespace std; void ComponentBase::write_to_stream(ostream&fd) const { fd << " component " << name_ << " is" << endl; - fd << " port(" << endl; - vector::const_iterator cur = ports_.begin(); - while (cur != ports_.end()) { - InterfacePort*item = *cur; - ++cur; + if(!parms_.empty()) { + fd << " generic(" << endl; - fd << " " << item->name << " : "; - switch (item->mode) { - case PORT_NONE: - fd << "???? "; - break; - case PORT_IN: - fd << "in "; - break; - case PORT_OUT: - fd << "out "; - break; - } + for(vector::const_iterator it = parms_.begin(); + it != parms_.end(); ++it) { + const InterfacePort*parm = *it; - item->type->write_to_stream(fd); + if(it != parms_.begin()) + fd << ";"; - if (cur != ports_.end()) - fd << ";" << endl; - else - fd << endl; + fd << " " << parm->name << " : "; + parm->type->write_to_stream(fd); + + if(parm->expr) { + fd << " := "; + parm->expr->write_to_stream(fd); + } + + fd << endl; + } + + fd << " );" << endl; } - fd << " );" << endl; + if(!ports_.empty()) { + fd << " port(" << endl; + + vector::const_iterator cur = ports_.begin(); + while (cur != ports_.end()) { + InterfacePort*item = *cur; + ++cur; + + fd << " " << item->name << " : "; + switch (item->mode) { + case PORT_NONE: + fd << "???? "; + break; + case PORT_IN: + fd << "in "; + break; + case PORT_OUT: + fd << "out "; + break; + } + + item->type->write_to_stream(fd); + + if (cur != ports_.end()) + fd << ";" << endl; + else + fd << endl; + } + + fd << " );" << endl; + } fd << " end component;" << endl; } From d3229b906832a85a7465cd3fc39424d894b849e8 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 6 Mar 2015 16:58:22 +0100 Subject: [PATCH 10/13] vhdlpp: 'string' type is emitted as 'string' instead of 'array <> of character'. --- vhdlpp/vtype_stream.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/vhdlpp/vtype_stream.cc b/vhdlpp/vtype_stream.cc index 6d24b6d74..f625f190a 100644 --- a/vhdlpp/vtype_stream.cc +++ b/vhdlpp/vtype_stream.cc @@ -38,13 +38,17 @@ void VType::write_type_to_stream(ostream&fd) const void VTypeArray::write_to_stream(ostream&fd) const { - // Special case: std_logic_vector + // 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 && + ranges_.size() == 1 && ranges_[0].is_box()) { + fd << "string"; + return; } bool typedefed = false; From 807ad8002d3f4af1f4e1bb8b2a72d9065da73e71 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 6 Mar 2015 16:59:30 +0100 Subject: [PATCH 11/13] vhdlpp: Check generics when searching through constants. --- vhdlpp/architec.cc | 41 +++++++++++++++++++++++++++++++++- vhdlpp/architec.h | 19 +++++++++++----- vhdlpp/architec_elaborate.cc | 4 ++++ vhdlpp/architec_emit.cc | 4 ++++ vhdlpp/expression_elaborate.cc | 8 ++++++- vhdlpp/expression_evaluate.cc | 5 ++--- vhdlpp/scope.h | 2 +- 7 files changed, 72 insertions(+), 11 deletions(-) diff --git a/vhdlpp/architec.cc b/vhdlpp/architec.cc index f223e8b90..b576af3b7 100644 --- a/vhdlpp/architec.cc +++ b/vhdlpp/architec.cc @@ -28,7 +28,7 @@ using namespace std; Architecture::Architecture(perm_string name, const ActiveScope&ref, list&s) -: Scope(ref), name_(name) +: Scope(ref), name_(name), cur_component_(NULL) { statements_.splice(statements_.end(), s); } @@ -39,6 +39,34 @@ Architecture::~Architecture() ScopeBase::cleanup(); } +bool Architecture::find_constant(perm_string by_name, const VType*&typ, Expression*&exp) const +{ + if(Scope::find_constant(by_name, typ, exp)) + return true; + + // Check generics in components + if(cur_component_) { + std::map::const_iterator c = new_components_.find(cur_component_->component_name()); + if(c == new_components_.end()) + c = old_components_.find(cur_component_->component_name()); + + assert(c != old_components_.end()); + ComponentBase*base = c->second; + + const InterfacePort*generic = base->find_generic(by_name); + if(!generic) + return false; // apparently there is no such generic in the component + + Expression*e = cur_component_->find_generic_map(by_name); + + typ = generic->type; + exp = e ? e : generic->expr; + return true; + } + + return false; +} + void Architecture::push_genvar_type(perm_string gname, const VType*gtype) { genvar_type_t tmp; @@ -191,6 +219,17 @@ ComponentInstantiation::~ComponentInstantiation() } } +Expression*ComponentInstantiation::find_generic_map(perm_string by_name) const +{ + map::const_iterator p = generic_map_.find(by_name); + + if(p == generic_map_.end()) + return NULL; + + return p->second; +} + + ProcessStatement::ProcessStatement(perm_string iname, std::list*sensitivity_list, std::list*statements_list) diff --git a/vhdlpp/architec.h b/vhdlpp/architec.h index 117038eab..491926568 100644 --- a/vhdlpp/architec.h +++ b/vhdlpp/architec.h @@ -25,7 +25,7 @@ # include # include -class ComponentBase; +class ComponentInstantiation; class Entity; class Expression; class ExpName; @@ -54,10 +54,6 @@ class Architecture : public Scope, public LineInfo { virtual int elaborate(Entity*ent, Architecture*arc); virtual int emit(ostream&out, Entity*ent, Architecture*arc); virtual void dump(ostream&out, int indent = 0) const; - - private: - - private: // Not implemented }; public: @@ -69,6 +65,10 @@ class Architecture : public Scope, public LineInfo { perm_string get_name() const { return name_; } + // Sets the currently processed component (to be able to reach its parameters). + void set_cur_component(ComponentInstantiation*component) { cur_component_ = component; } + bool find_constant(perm_string by_name, const VType*&typ, Expression*&exp) const; + // Elaborate this architecture in the context of the given entity. int elaborate(Entity*entity); @@ -110,6 +110,9 @@ class Architecture : public Scope, public LineInfo { }; std::list genvar_emit_stack_; + // Currently processed component (or NULL if none). + ComponentInstantiation*cur_component_; + private: // Not implemented }; @@ -198,6 +201,12 @@ class ComponentInstantiation : public Architecture::Statement { virtual int emit(ostream&out, Entity*entity, Architecture*arc); virtual void dump(ostream&out, int indent =0) const; + // Returns the expression that initalizes a generic (or NULL if not found). + Expression*find_generic_map(perm_string by_name) const; + + inline perm_string instance_name() const { return iname_; } + inline perm_string component_name() const { return cname_; } + private: perm_string iname_; perm_string cname_; diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index bdbd206dd..9ab09bfa8 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -92,6 +92,8 @@ int ComponentInstantiation::elaborate(Entity*ent, Architecture*arc) return 1; } + arc->set_cur_component(this); + for (map::const_iterator cur = generic_map_.begin() ; cur != generic_map_.end() ; ++cur) { // check if generic from component instantiation @@ -133,6 +135,8 @@ int ComponentInstantiation::elaborate(Entity*ent, Architecture*arc) cur->second->elaborate_expr(ent, arc, iport->type); } + arc->set_cur_component(NULL); + return errors; } diff --git a/vhdlpp/architec_emit.cc b/vhdlpp/architec_emit.cc index 93b9fe2b9..cf18cdd84 100644 --- a/vhdlpp/architec_emit.cc +++ b/vhdlpp/architec_emit.cc @@ -148,6 +148,8 @@ int ComponentInstantiation::emit(ostream&out, Entity*ent, Architecture*arc) const char*comma = ""; int errors = 0; + arc->set_cur_component(this); + out << cname_; if (! generic_map_.empty()) { out << " #("; @@ -177,6 +179,8 @@ int ComponentInstantiation::emit(ostream&out, Entity*ent, Architecture*arc) } out << ");" << endl; + arc->set_cur_component(NULL); + return errors; } diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 19c79b591..e4389caca 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -273,6 +273,9 @@ int ExpName::elaborate_rval(Entity*ent, ScopeBase*scope, const InterfacePort*lva errors += 1; } + const VType*dummy_type; + Expression*dummy_expr; + if (const InterfacePort*cur = ent->find_port(name_)) { /* IEEE 1076-2008, p.80: * For a formal port IN, associated port should be IN, OUT, INOUT or BUFFER @@ -301,8 +304,11 @@ int ExpName::elaborate_rval(Entity*ent, ScopeBase*scope, const InterfacePort*lva } else if (ent->find_generic(name_)) { /* OK */ + } else if (scope->find_constant(name_, dummy_type, dummy_expr)) { + /* OK */ + } else { - cerr << get_fileline() << ": error: No port or signal " << name_ + cerr << get_fileline() << ": error: No port, signal or constant " << name_ << " to be used as r-value." << endl; errors += 1; } diff --git a/vhdlpp/expression_evaluate.cc b/vhdlpp/expression_evaluate.cc index 2d498c020..983c0ed6b 100644 --- a/vhdlpp/expression_evaluate.cc +++ b/vhdlpp/expression_evaluate.cc @@ -182,11 +182,10 @@ bool ExpName::evaluate(ScopeBase*scope, int64_t&val) const return false; } - if(!scope) + if (!scope) return false; - bool rc = scope->find_constant(name_, type, exp); - if (rc == false) + if (!scope->find_constant(name_, type, exp)) return false; return exp->evaluate(scope, val); diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index 5f1d4c33a..918121158 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -53,7 +53,7 @@ class ScopeBase { virtual ~ScopeBase() =0; const VType* find_type(perm_string by_name); - bool find_constant(perm_string by_name, const VType*&typ, Expression*&exp) const; + virtual bool find_constant(perm_string by_name, const VType*&typ, Expression*&exp) const; 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; From 295e4e7dfbfc7c0400c447289c3e75780ce7b48f Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 6 Mar 2015 19:30:02 +0100 Subject: [PATCH 12/13] vhdlpp: Fixed crash on unassociated generics. --- vhdlpp/entity_elaborate.cc | 3 ++- vhdlpp/entity_emit.cc | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/vhdlpp/entity_elaborate.cc b/vhdlpp/entity_elaborate.cc index 861029ca7..4d74d0039 100644 --- a/vhdlpp/entity_elaborate.cc +++ b/vhdlpp/entity_elaborate.cc @@ -92,7 +92,8 @@ int Entity::elaborate_generic_exprs_() for (vector::const_iterator cur = parms_.begin() ; cur != parms_.end() ; ++cur) { InterfacePort*curp = *cur; - curp->expr->elaborate_expr(this, 0, curp->type); + if(curp->expr) + curp->expr->elaborate_expr(this, 0, curp->type); } return errors; } diff --git a/vhdlpp/entity_emit.cc b/vhdlpp/entity_emit.cc index 41fb1eef8..268b36f7d 100644 --- a/vhdlpp/entity_emit.cc +++ b/vhdlpp/entity_emit.cc @@ -50,9 +50,11 @@ int Entity::emit(ostream&out) 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 << "parameter \\" << curp->name << " "; + if(curp->expr) { + out << "= "; + errors += curp->expr->emit(out, this, 0); + } } out << ") "; } From d1dc98b7f73c21e4eae4bde91855ef5f41059dde Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Sat, 7 Mar 2015 20:47:20 +0100 Subject: [PATCH 13/13] vhdlpp: Changed the workaround for accessing localparam arrays & records. --- vhdlpp/expression_emit.cc | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index bb88ddfe5..1d8af85b2 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -854,22 +854,15 @@ int ExpName::emit_workaround_(ostream&out, Entity*ent, ScopeBase*scope, { int errors = 0; - out << "{"; - for(int i = field_size - 1; i >= 0; --i) { - if(i != field_size - 1) - out << ","; + out << "\\" << (prefix_.get() ? prefix_->name_ : name_) << " ["; - out << "\\" << (prefix_.get() ? prefix_->name_ : name_) << " ["; - - for(list::const_iterator it = indices.begin(); - it != indices.end(); ++it) { - errors += (*it)->emit(out, ent, scope); - out << " + "; - } - - out << i << "]"; + for(list::const_iterator it = indices.begin(); + it != indices.end(); ++it) { + errors += (*it)->emit(out, ent, scope); + out << "+"; } - out << "}"; + + out << ":" << field_size << "]"; return errors; }