From afbda099fbd0e83213dd41bd823c5e4115290037 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 24 Feb 2015 16:06:55 +0100 Subject: [PATCH] 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_;