vhdlpp: Workaround to handle constant arrays of vectors & records.

This commit is contained in:
Maciej Suminski 2015-02-24 16:06:55 +01:00
parent 4b0d220671
commit afbda099fb
7 changed files with 172 additions and 56 deletions

View File

@ -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<const ExpName*> (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)
{

View File

@ -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<index_t*>&indices, int&data_size);
bool check_const_array_workaround_(const VTypeArray*arr, list<index_t*>&indices,
int&data_size) const;
bool check_const_record_workaround_(const VTypeRecord*rec, list<index_t*>&indices,
int&data_size) const;
int emit_workaround_(ostream&out, Entity*ent, ScopeBase*scope,
const list<index_t*>&indices, int field_size);
private:
std::auto_ptr<ExpName> prefix_;

View File

@ -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<index_t*> 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<Architecture*>(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<index_t*>& 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<const VTypeArray*>(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<const VTypeDef*>(type)) {
type = type_def->peek_definition();
}
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(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<const VTypeArray*>(type);
assert(arr);
type = arr->element_type();
data_size = type->get_width();
}
while(const VTypeDef*type_def = dynamic_cast<const VTypeDef*>(type)) {
type = type_def->peek_definition();
}
const VTypeRecord*rec = dynamic_cast<const VTypeRecord*>(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<index_t*>&indices, int&data_size) const
{
const VType*element = arr->element_type();
const VTypeArray*arr_element = dynamic_cast<const VTypeArray*>(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<index_t*>&indices, int&data_size) const
{
int tmp_offset = 0;
const vector<VTypeRecord::element_t*>& elements = rec->get_elements();
for(vector<VTypeRecord::element_t*>::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<const VTypeArray*>(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<index_t*>& 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<index_t*>::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

View File

@ -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;

View File

@ -1601,11 +1601,16 @@ name /* IEEE 1076-2008 P8.1 */
delete[]$1;
$$ = tmp;
}
| selected_name '(' range ')'
| selected_name '(' range ')'
{ ExpName*tmp = dynamic_cast<ExpName*> ($1);
tmp->set_range($3->msb(), $3->lsb());
$$ = tmp;
}
| selected_name '(' expression ')'
{ ExpName*tmp = dynamic_cast<ExpName*> ($1);
tmp->set_range($3, NULL);
$$ = tmp;
}
;
/* Handle name lists as lists of expressions. */

View File

@ -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 {

View File

@ -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<element_t*> get_elements() const { return elements_; }
private:
std::vector<element_t*> elements_;