vhdlpp: Workaround to handle constant arrays of vectors & records.
This commit is contained in:
parent
4b0d220671
commit
afbda099fb
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
|
* 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)
|
* Maciej Suminski (maciej.suminski@cern.ch)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* This source code is free software; you can redistribute it
|
||||||
|
|
@ -450,11 +450,6 @@ ExpName::~ExpName()
|
||||||
delete index_;
|
delete index_;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* ExpName::name() const
|
|
||||||
{
|
|
||||||
return name_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ExpName::symbolic_compare(const Expression*that) const
|
bool ExpName::symbolic_compare(const Expression*that) const
|
||||||
{
|
{
|
||||||
const ExpName*that_name = dynamic_cast<const ExpName*> (that);
|
const ExpName*that_name = dynamic_cast<const ExpName*> (that);
|
||||||
|
|
@ -485,6 +480,28 @@ void ExpName::set_range(Expression*msb, Expression*lsb)
|
||||||
lsb_ = 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)
|
ExpRelation::ExpRelation(ExpRelation::fun_t ty, Expression*op1, Expression*op2)
|
||||||
: ExpBinary(op1, op2), fun_(ty)
|
: ExpBinary(op1, op2), fun_(ty)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#define IVL_expression_H
|
#define IVL_expression_H
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com)
|
* 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)
|
* Maciej Suminski (maciej.suminski@cern.ch)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* 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(ScopeBase*scope, int64_t&val) const;
|
||||||
virtual bool evaluate(Entity*ent, 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
|
// The symbolic compare returns true if the two expressions
|
||||||
// are equal without actually calculating the value.
|
// are equal without actually calculating the value.
|
||||||
virtual bool symbolic_compare(const Expression*that) const;
|
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 evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
|
||||||
bool symbolic_compare(const Expression*that) const;
|
bool symbolic_compare(const Expression*that) const;
|
||||||
void dump(ostream&out, int indent = 0) 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_; }
|
inline const perm_string& peek_name() const { return name_; }
|
||||||
|
|
||||||
void set_range(Expression*msb, Expression*lsb);
|
void set_range(Expression*msb, Expression*lsb);
|
||||||
|
|
||||||
private:
|
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);
|
const VType* elaborate_adjust_type_with_range_(Entity*ent, ScopeBase*scope, const VType*type);
|
||||||
|
|
||||||
int elaborate_lval_(Entity*ent, ScopeBase*scope, bool, ExpName*suffix);
|
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);
|
int emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope);
|
||||||
|
|
||||||
// Constant arrays of vectors are flattened into a single localparam,
|
// There are some workarounds required for constant arrays/records, as
|
||||||
// therefore indices of such localparam point to a bit, not a word.
|
// they are currently emitted as flat localparams (without any type
|
||||||
// The following workaround expands expressions to a concatenation of
|
// information). The following workarounds adjust the access indices
|
||||||
// bits making the requested word.
|
// to select appropriate parts of the localparam.
|
||||||
bool emit_const_array_workaround_(ostream&out, Entity*ent, ScopeBase*scope) const;
|
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:
|
private:
|
||||||
std::auto_ptr<ExpName> prefix_;
|
std::auto_ptr<ExpName> prefix_;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
|
* 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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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 ExpName::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
{
|
{
|
||||||
int errors = 0;
|
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()) {
|
if (prefix_.get()) {
|
||||||
errors += prefix_->emit_as_prefix_(out, ent, scope);
|
errors += prefix_->emit_as_prefix_(out, ent, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(index_ && emit_const_array_workaround_(out, ent, scope))
|
|
||||||
return errors;
|
|
||||||
|
|
||||||
const GenerateStatement*gs = 0;
|
const GenerateStatement*gs = 0;
|
||||||
Architecture*arc = dynamic_cast<Architecture*>(scope);
|
Architecture*arc = dynamic_cast<Architecture*>(scope);
|
||||||
if (arc && (gs = arc->probe_genvar_emit(name_)))
|
if (arc && (gs = arc->probe_genvar_emit(name_)))
|
||||||
|
|
@ -739,60 +744,123 @@ int ExpName::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
return errors;
|
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;
|
Expression*exp = NULL;
|
||||||
|
bool wrkand_required = false;
|
||||||
|
const VType*type = NULL;
|
||||||
|
|
||||||
if(!scope)
|
if(!scope)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(!scope->find_constant(name_, type, exp))
|
if(prefix_.get())
|
||||||
return false;
|
prefix_->try_workarounds_(out, ent, scope, indices, data_size);
|
||||||
|
|
||||||
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(type);
|
if(index_ && !lsb_ && scope->find_constant(name_, type, exp)) {
|
||||||
ivl_assert(*this, arr); // if there is an index, it should be an array, right?
|
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 VType*element = arr->element_type();
|
||||||
const VTypeArray*arr_element = dynamic_cast<const VTypeArray*>(element);
|
data_size = element->get_width();
|
||||||
if(!arr_element) {
|
indices.push_back(new index_t(index_, new ExpInteger(data_size)));
|
||||||
// index adjustments are not necessary, it is not an array of vectors
|
return true;
|
||||||
return false;
|
}
|
||||||
|
|
||||||
|
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);
|
return false;
|
||||||
if(arr_element->dimensions() != 1) {
|
}
|
||||||
cerr << get_fileline() << ": Sorry, only one-dimensional constant arrays are handled." << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t start_val;
|
int ExpName::emit_workaround_(ostream&out, Entity*ent, ScopeBase*scope,
|
||||||
bool start_rc = arr_element->dimension(0).msb()->evaluate(ent, scope, start_val);
|
const list<index_t*>& indices, int field_size)
|
||||||
|
{
|
||||||
int64_t finish_val;
|
int errors = 0;
|
||||||
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 << "{";
|
out << "{";
|
||||||
for(int i = finish_val; i >= start_val; --i) {
|
for(int i = field_size - 1; i >= 0; --i) {
|
||||||
if(i != finish_val)
|
if(i != field_size - 1)
|
||||||
out << ",";
|
out << ",";
|
||||||
|
|
||||||
out << "\\" << name_ << " [" << word_size << "*";
|
out << "\\" << (prefix_.get() ? prefix_->name_ : name_) << " [";
|
||||||
index_->emit(out, ent, scope);
|
|
||||||
out << "+" << i << "]";
|
for(list<index_t*>::const_iterator it = indices.begin();
|
||||||
|
it != indices.end(); ++it) {
|
||||||
|
errors += (*it)->emit(out, ent, scope);
|
||||||
|
out << " + ";
|
||||||
|
}
|
||||||
|
|
||||||
|
out << i << "]";
|
||||||
}
|
}
|
||||||
out << "}";
|
out << "}";
|
||||||
|
|
||||||
return true;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExpName::is_primary(void) const
|
bool ExpName::is_primary(void) const
|
||||||
|
|
|
||||||
|
|
@ -191,6 +191,9 @@ bool ExpName::evaluate(ScopeBase*scope, int64_t&val) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!scope)
|
||||||
|
return false;
|
||||||
|
|
||||||
bool rc = scope->find_constant(name_, type, exp);
|
bool rc = scope->find_constant(name_, type, exp);
|
||||||
if (rc == false)
|
if (rc == false)
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -1601,11 +1601,16 @@ name /* IEEE 1076-2008 P8.1 */
|
||||||
delete[]$1;
|
delete[]$1;
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| selected_name '(' range ')'
|
| selected_name '(' range ')'
|
||||||
{ ExpName*tmp = dynamic_cast<ExpName*> ($1);
|
{ ExpName*tmp = dynamic_cast<ExpName*> ($1);
|
||||||
tmp->set_range($3->msb(), $3->lsb());
|
tmp->set_range($3->msb(), $3->lsb());
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
|
| selected_name '(' expression ')'
|
||||||
|
{ ExpName*tmp = dynamic_cast<ExpName*> ($1);
|
||||||
|
tmp->set_range($3, NULL);
|
||||||
|
$$ = tmp;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
/* Handle name lists as lists of expressions. */
|
/* Handle name lists as lists of expressions. */
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,7 @@ int VTypeArray::get_width() const
|
||||||
int64_t msb_val, lsb_val;
|
int64_t msb_val, lsb_val;
|
||||||
|
|
||||||
if(dim.is_box())
|
if(dim.is_box())
|
||||||
return false;
|
return -1;
|
||||||
|
|
||||||
if(!dim.msb()->evaluate(NULL, msb_val))
|
if(!dim.msb()->evaluate(NULL, msb_val))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -217,7 +217,7 @@ int VTypeArray::get_width() const
|
||||||
size *= 1 + labs(msb_val - lsb_val);
|
size *= 1 + labs(msb_val - lsb_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
return etype_->get_width() * size;
|
return element_type()->get_width() * size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VTypeArray::is_unbounded() const {
|
bool VTypeArray::is_unbounded() const {
|
||||||
|
|
|
||||||
|
|
@ -346,6 +346,7 @@ class VTypeRecord : public VType {
|
||||||
|
|
||||||
bool can_be_packed() const { return true; }
|
bool can_be_packed() const { return true; }
|
||||||
const element_t* element_by_name(perm_string name, int*index = NULL) const;
|
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:
|
private:
|
||||||
std::vector<element_t*> elements_;
|
std::vector<element_t*> elements_;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue