commit
437dc10341
|
|
@ -28,7 +28,7 @@ using namespace std;
|
||||||
|
|
||||||
Architecture::Architecture(perm_string name, const ActiveScope&ref,
|
Architecture::Architecture(perm_string name, const ActiveScope&ref,
|
||||||
list<Architecture::Statement*>&s)
|
list<Architecture::Statement*>&s)
|
||||||
: Scope(ref), name_(name)
|
: Scope(ref), name_(name), cur_component_(NULL)
|
||||||
{
|
{
|
||||||
statements_.splice(statements_.end(), s);
|
statements_.splice(statements_.end(), s);
|
||||||
}
|
}
|
||||||
|
|
@ -39,6 +39,34 @@ Architecture::~Architecture()
|
||||||
ScopeBase::cleanup();
|
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<perm_string,ComponentBase*>::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)
|
void Architecture::push_genvar_type(perm_string gname, const VType*gtype)
|
||||||
{
|
{
|
||||||
genvar_type_t tmp;
|
genvar_type_t tmp;
|
||||||
|
|
@ -191,6 +219,17 @@ ComponentInstantiation::~ComponentInstantiation()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expression*ComponentInstantiation::find_generic_map(perm_string by_name) const
|
||||||
|
{
|
||||||
|
map<perm_string,Expression*>::const_iterator p = generic_map_.find(by_name);
|
||||||
|
|
||||||
|
if(p == generic_map_.end())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return p->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ProcessStatement::ProcessStatement(perm_string iname,
|
ProcessStatement::ProcessStatement(perm_string iname,
|
||||||
std::list<Expression*>*sensitivity_list,
|
std::list<Expression*>*sensitivity_list,
|
||||||
std::list<SequentialStmt*>*statements_list)
|
std::list<SequentialStmt*>*statements_list)
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
# include <list>
|
# include <list>
|
||||||
# include <map>
|
# include <map>
|
||||||
|
|
||||||
class ComponentBase;
|
class ComponentInstantiation;
|
||||||
class Entity;
|
class Entity;
|
||||||
class Expression;
|
class Expression;
|
||||||
class ExpName;
|
class ExpName;
|
||||||
|
|
@ -54,10 +54,6 @@ class Architecture : public Scope, public LineInfo {
|
||||||
virtual int elaborate(Entity*ent, Architecture*arc);
|
virtual int elaborate(Entity*ent, Architecture*arc);
|
||||||
virtual int emit(ostream&out, Entity*ent, Architecture*arc);
|
virtual int emit(ostream&out, Entity*ent, Architecture*arc);
|
||||||
virtual void dump(ostream&out, int indent = 0) const;
|
virtual void dump(ostream&out, int indent = 0) const;
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
private: // Not implemented
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -69,6 +65,10 @@ class Architecture : public Scope, public LineInfo {
|
||||||
|
|
||||||
perm_string get_name() const { return name_; }
|
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.
|
// Elaborate this architecture in the context of the given entity.
|
||||||
int elaborate(Entity*entity);
|
int elaborate(Entity*entity);
|
||||||
|
|
||||||
|
|
@ -110,6 +110,9 @@ class Architecture : public Scope, public LineInfo {
|
||||||
};
|
};
|
||||||
std::list<genvar_emit_t> genvar_emit_stack_;
|
std::list<genvar_emit_t> genvar_emit_stack_;
|
||||||
|
|
||||||
|
// Currently processed component (or NULL if none).
|
||||||
|
ComponentInstantiation*cur_component_;
|
||||||
|
|
||||||
private: // Not implemented
|
private: // Not implemented
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -198,6 +201,12 @@ class ComponentInstantiation : public Architecture::Statement {
|
||||||
virtual int emit(ostream&out, Entity*entity, Architecture*arc);
|
virtual int emit(ostream&out, Entity*entity, Architecture*arc);
|
||||||
virtual void dump(ostream&out, int indent =0) const;
|
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:
|
private:
|
||||||
perm_string iname_;
|
perm_string iname_;
|
||||||
perm_string cname_;
|
perm_string cname_;
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,8 @@ int ComponentInstantiation::elaborate(Entity*ent, Architecture*arc)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
arc->set_cur_component(this);
|
||||||
|
|
||||||
for (map<perm_string,Expression*>::const_iterator cur = generic_map_.begin()
|
for (map<perm_string,Expression*>::const_iterator cur = generic_map_.begin()
|
||||||
; cur != generic_map_.end() ; ++cur) {
|
; cur != generic_map_.end() ; ++cur) {
|
||||||
// check if generic from component instantiation
|
// 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);
|
cur->second->elaborate_expr(ent, arc, iport->type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
arc->set_cur_component(NULL);
|
||||||
|
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,8 @@ int ComponentInstantiation::emit(ostream&out, Entity*ent, Architecture*arc)
|
||||||
const char*comma = "";
|
const char*comma = "";
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
|
|
||||||
|
arc->set_cur_component(this);
|
||||||
|
|
||||||
out << cname_;
|
out << cname_;
|
||||||
if (! generic_map_.empty()) {
|
if (! generic_map_.empty()) {
|
||||||
out << " #(";
|
out << " #(";
|
||||||
|
|
@ -177,6 +179,8 @@ int ComponentInstantiation::emit(ostream&out, Entity*ent, Architecture*arc)
|
||||||
}
|
}
|
||||||
out << ");" << endl;
|
out << ");" << endl;
|
||||||
|
|
||||||
|
arc->set_cur_component(NULL);
|
||||||
|
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,8 @@ int Entity::elaborate_generic_exprs_()
|
||||||
for (vector<InterfacePort*>::const_iterator cur = parms_.begin()
|
for (vector<InterfacePort*>::const_iterator cur = parms_.begin()
|
||||||
; cur != parms_.end() ; ++cur) {
|
; cur != parms_.end() ; ++cur) {
|
||||||
InterfacePort*curp = *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;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,11 @@ int Entity::emit(ostream&out)
|
||||||
const InterfacePort*curp = *cur;
|
const InterfacePort*curp = *cur;
|
||||||
if (cur != parms_.begin())
|
if (cur != parms_.begin())
|
||||||
out << ", ";
|
out << ", ";
|
||||||
out << "parameter \\" << curp->name << " = ";
|
out << "parameter \\" << curp->name << " ";
|
||||||
ivl_assert(*this, curp->expr);
|
if(curp->expr) {
|
||||||
errors += curp->expr->emit(out, this, 0);
|
out << "= ";
|
||||||
|
errors += curp->expr->emit(out, this, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out << ") ";
|
out << ") ";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,40 +18,68 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
# include "entity.h"
|
# include "entity.h"
|
||||||
|
# include "expression.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
void ComponentBase::write_to_stream(ostream&fd) const
|
void ComponentBase::write_to_stream(ostream&fd) const
|
||||||
{
|
{
|
||||||
fd << " component " << name_ << " is" << endl;
|
fd << " component " << name_ << " is" << endl;
|
||||||
fd << " port(" << endl;
|
|
||||||
|
|
||||||
vector<InterfacePort*>::const_iterator cur = ports_.begin();
|
if(!parms_.empty()) {
|
||||||
while (cur != ports_.end()) {
|
fd << " generic(" << endl;
|
||||||
InterfacePort*item = *cur;
|
|
||||||
++cur;
|
|
||||||
|
|
||||||
fd << " " << item->name << " : ";
|
for(vector<InterfacePort*>::const_iterator it = parms_.begin();
|
||||||
switch (item->mode) {
|
it != parms_.end(); ++it) {
|
||||||
case PORT_NONE:
|
const InterfacePort*parm = *it;
|
||||||
fd << "???? ";
|
|
||||||
break;
|
|
||||||
case PORT_IN:
|
|
||||||
fd << "in ";
|
|
||||||
break;
|
|
||||||
case PORT_OUT:
|
|
||||||
fd << "out ";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
item->type->write_to_stream(fd);
|
if(it != parms_.begin())
|
||||||
|
fd << ";";
|
||||||
|
|
||||||
if (cur != ports_.end())
|
fd << " " << parm->name << " : ";
|
||||||
fd << ";" << endl;
|
parm->type->write_to_stream(fd);
|
||||||
else
|
|
||||||
fd << endl;
|
if(parm->expr) {
|
||||||
|
fd << " := ";
|
||||||
|
parm->expr->write_to_stream(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
fd << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd << " );" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd << " );" << endl;
|
if(!ports_.empty()) {
|
||||||
|
fd << " port(" << endl;
|
||||||
|
|
||||||
|
vector<InterfacePort*>::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;
|
fd << " end component;" << endl;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,6 +661,22 @@ class ExpName : public Expression {
|
||||||
|
|
||||||
int emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope);
|
int emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope);
|
||||||
|
|
||||||
|
// 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, ScopeBase*scope,
|
||||||
|
list<index_t*>&indices, int&data_size) const;
|
||||||
|
|
||||||
|
bool check_const_record_workaround_(const VTypeRecord*rec, ScopeBase*scope,
|
||||||
|
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_;
|
||||||
perm_string name_;
|
perm_string name_;
|
||||||
|
|
|
||||||
|
|
@ -273,6 +273,9 @@ int ExpName::elaborate_rval(Entity*ent, ScopeBase*scope, const InterfacePort*lva
|
||||||
errors += 1;
|
errors += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const VType*dummy_type;
|
||||||
|
Expression*dummy_expr;
|
||||||
|
|
||||||
if (const InterfacePort*cur = ent->find_port(name_)) {
|
if (const InterfacePort*cur = ent->find_port(name_)) {
|
||||||
/* IEEE 1076-2008, p.80:
|
/* IEEE 1076-2008, p.80:
|
||||||
* For a formal port IN, associated port should be IN, OUT, INOUT or BUFFER
|
* 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_)) {
|
} else if (ent->find_generic(name_)) {
|
||||||
/* OK */
|
/* OK */
|
||||||
|
|
||||||
|
} else if (scope->find_constant(name_, dummy_type, dummy_expr)) {
|
||||||
|
/* OK */
|
||||||
|
|
||||||
} else {
|
} 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;
|
<< " to be used as r-value." << endl;
|
||||||
errors += 1;
|
errors += 1;
|
||||||
}
|
}
|
||||||
|
|
@ -922,87 +928,13 @@ const VType* ExpName::fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*)co
|
||||||
return probe_type(ent, scope);
|
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) {
|
if (ltype) {
|
||||||
ivl_assert(*this, ltype != 0);
|
ivl_assert(*this, ltype != 0);
|
||||||
set_type(ltype);
|
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<const VTypeArray*>(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<const VTypeArray*>(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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -306,6 +307,13 @@ int ExpAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
{
|
{
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
|
|
||||||
|
// Try to evaluate first
|
||||||
|
int64_t val;
|
||||||
|
if(evaluate(scope, val)) {
|
||||||
|
out << val;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (name_ == "event") {
|
if (name_ == "event") {
|
||||||
out << "$ivlh_attribute_event(";
|
out << "$ivlh_attribute_event(";
|
||||||
errors += base_->emit(out, ent, scope);
|
errors += base_->emit(out, ent, scope);
|
||||||
|
|
@ -552,12 +560,13 @@ int ExpFunc::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
{
|
{
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
|
|
||||||
// SystemVerilog takes care of signs, depending on the lvalue
|
// SystemVerilog takes care of sign & width, depending on the lvalue type
|
||||||
if (name_ == "to_integer" && argv_.size()==1) {
|
if ((name_ == "to_integer" && argv_.size() == 1) ||
|
||||||
|
(name_ == "resize" && argv_.size() == 2)) {
|
||||||
errors += argv_[0]->emit(out, ent, scope);
|
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
|
// Handle the special case that this is a cast to
|
||||||
// unsigned. This function is brought in as part of the
|
// unsigned. This function is brought in as part of the
|
||||||
// std numeric library, but we interpret it as the same
|
// std numeric library, but we interpret it as the same
|
||||||
|
|
@ -710,6 +719,13 @@ 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);
|
||||||
|
|
@ -736,6 +752,121 @@ int ExpName::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ExpName::try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope,
|
||||||
|
list<index_t*>& indices, int& data_size)
|
||||||
|
{
|
||||||
|
Expression*exp = NULL;
|
||||||
|
bool wrkand_required = false;
|
||||||
|
const VType*type = NULL;
|
||||||
|
|
||||||
|
if(!scope)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(prefix_.get())
|
||||||
|
prefix_->try_workarounds_(out, ent, scope, indices, data_size);
|
||||||
|
|
||||||
|
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, scope, 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(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
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, scope, indices, data_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return wrkand_required;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExpName::check_const_array_workaround_(const VTypeArray*arr,
|
||||||
|
ScopeBase*scope, list<index_t*>&indices, int&data_size) const
|
||||||
|
{
|
||||||
|
const VType*element = arr->element_type();
|
||||||
|
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,
|
||||||
|
ScopeBase*scope, 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(scope);
|
||||||
|
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, scope, indices, data_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int w = el->peek_type()->get_width(scope);
|
||||||
|
|
||||||
|
if(w < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
tmp_offset += w;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ExpName::emit_workaround_(ostream&out, Entity*ent, ScopeBase*scope,
|
||||||
|
const list<index_t*>& indices, int field_size)
|
||||||
|
{
|
||||||
|
int errors = 0;
|
||||||
|
|
||||||
|
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 << ":" << field_size << "]";
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
bool ExpName::is_primary(void) const
|
bool ExpName::is_primary(void) const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@ bool Expression::evaluate(Entity*, ScopeBase*scope, int64_t&val) const
|
||||||
return evaluate(scope, val);
|
return evaluate(scope, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ExpArithmetic::evaluate(ScopeBase*scope, int64_t&val) const
|
bool ExpArithmetic::evaluate(ScopeBase*scope, int64_t&val) const
|
||||||
{
|
{
|
||||||
int64_t val1, val2;
|
int64_t val1, val2;
|
||||||
|
|
@ -113,20 +112,12 @@ bool ExpAttribute::evaluate(ScopeBase*scope, int64_t&val) const
|
||||||
}
|
}
|
||||||
|
|
||||||
if(name_ == "length") {
|
if(name_ == "length") {
|
||||||
int64_t size = 1;
|
int64_t size = arr->get_width(scope);
|
||||||
for (size_t idx = 0 ; idx < arr->dimensions() ; idx += 1) {
|
|
||||||
const VTypeArray::range_t&dim = arr->dimension(idx);
|
|
||||||
int64_t msb_val, lsb_val;
|
|
||||||
|
|
||||||
if(dim.is_box())
|
if(size > 0)
|
||||||
return false;
|
val = size;
|
||||||
|
else
|
||||||
dim.msb()->evaluate(scope, msb_val);
|
return false;
|
||||||
dim.lsb()->evaluate(scope, lsb_val);
|
|
||||||
|
|
||||||
size *= 1 + labs(msb_val - lsb_val);
|
|
||||||
}
|
|
||||||
val = size;
|
|
||||||
} else if(name_ == "left") {
|
} else if(name_ == "left") {
|
||||||
arr->dimension(0).msb()->evaluate(scope, val);
|
arr->dimension(0).msb()->evaluate(scope, val);
|
||||||
} else if(name_ == "right") {
|
} else if(name_ == "right") {
|
||||||
|
|
@ -191,8 +182,10 @@ bool ExpName::evaluate(ScopeBase*scope, int64_t&val) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rc = scope->find_constant(name_, type, exp);
|
if (!scope)
|
||||||
if (rc == false)
|
return false;
|
||||||
|
|
||||||
|
if (!scope->find_constant(name_, type, exp))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return exp->evaluate(scope, val);
|
return exp->evaluate(scope, val);
|
||||||
|
|
|
||||||
|
|
@ -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. */
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ class ScopeBase {
|
||||||
virtual ~ScopeBase() =0;
|
virtual ~ScopeBase() =0;
|
||||||
|
|
||||||
const VType* find_type(perm_string by_name);
|
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;
|
Signal* find_signal(perm_string by_name) const;
|
||||||
Variable* find_variable(perm_string by_name) const;
|
Variable* find_variable(perm_string by_name) const;
|
||||||
virtual const InterfacePort* find_param(perm_string by_name) const;
|
virtual const InterfacePort* find_param(perm_string by_name) const;
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,25 @@ void VTypePrimitive::show(ostream&out) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int VTypePrimitive::get_width(ScopeBase*) const
|
||||||
|
{
|
||||||
|
switch(type_) {
|
||||||
|
case BOOLEAN:
|
||||||
|
case BIT:
|
||||||
|
case STDLOGIC:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case INTEGER:
|
||||||
|
case NATURAL:
|
||||||
|
return 32;
|
||||||
|
|
||||||
|
case CHARACTER:
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
VTypeArray::range_t*VTypeArray::range_t::clone() const
|
VTypeArray::range_t*VTypeArray::range_t::clone() const
|
||||||
{
|
{
|
||||||
return new VTypeArray::range_t(safe_clone(msb_), safe_clone(lsb_), direction_);
|
return new VTypeArray::range_t(safe_clone(msb_), safe_clone(lsb_), direction_);
|
||||||
|
|
@ -176,6 +195,30 @@ void VTypeArray::show(ostream&out) const
|
||||||
out << "<nil>";
|
out << "<nil>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int VTypeArray::get_width(ScopeBase*scope) const
|
||||||
|
{
|
||||||
|
int64_t size = 1;
|
||||||
|
|
||||||
|
for(vector<range_t>::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 -1;
|
||||||
|
|
||||||
|
if(!dim.msb()->evaluate(scope, msb_val))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if(!dim.lsb()->evaluate(scope, lsb_val))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
size *= 1 + labs(msb_val - lsb_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
return element_type()->get_width(scope) * size;
|
||||||
|
}
|
||||||
|
|
||||||
bool VTypeArray::is_unbounded() const {
|
bool VTypeArray::is_unbounded() const {
|
||||||
for(std::vector<range_t>::const_iterator it = ranges_.begin();
|
for(std::vector<range_t>::const_iterator it = ranges_.begin();
|
||||||
it != ranges_.end(); ++it)
|
it != ranges_.end(); ++it)
|
||||||
|
|
@ -281,6 +324,23 @@ void VTypeRecord::show(ostream&out) const
|
||||||
write_to_stream(out);
|
write_to_stream(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int VTypeRecord::get_width(ScopeBase*scope) const
|
||||||
|
{
|
||||||
|
int width = 0;
|
||||||
|
|
||||||
|
for(vector<element_t*>::const_iterator it = elements_.begin();
|
||||||
|
it != elements_.end(); ++it) {
|
||||||
|
int w = (*it)->peek_type()->get_width(scope);
|
||||||
|
|
||||||
|
if(w < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
width += w;
|
||||||
|
}
|
||||||
|
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
const VTypeRecord::element_t* VTypeRecord::element_by_name(perm_string name, int*index) const
|
const VTypeRecord::element_t* VTypeRecord::element_by_name(perm_string name, int*index) const
|
||||||
{
|
{
|
||||||
for (vector<element_t*>::const_iterator cur = elements_.begin()
|
for (vector<element_t*>::const_iterator cur = elements_.begin()
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ class VType {
|
||||||
// of this type to the designated stream. This is used for
|
// of this type to the designated stream. This is used for
|
||||||
// writing parsed types to library files.
|
// writing parsed types to library files.
|
||||||
virtual void write_to_stream(std::ostream&fd) const;
|
virtual void write_to_stream(std::ostream&fd) const;
|
||||||
|
|
||||||
// This is like the above, but is the root function called
|
// This is like the above, but is the root function called
|
||||||
// directly after the "type <name> is..." when writing type
|
// directly after the "type <name> is..." when writing type
|
||||||
// definitions. Most types accept the default definition of this.
|
// definitions. Most types accept the default definition of this.
|
||||||
|
|
@ -100,6 +101,10 @@ class VType {
|
||||||
// typedefs (i.e. not ones defined by the user).
|
// typedefs (i.e. not ones defined by the user).
|
||||||
perm_string get_generic_typename() const;
|
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(ScopeBase*) const { return -1; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend struct decl_t;
|
friend struct decl_t;
|
||||||
// This virtual method is called to emit the declaration. This
|
// 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 write_to_stream(std::ostream&fd) const;
|
||||||
void show(std::ostream&) const;
|
void show(std::ostream&) const;
|
||||||
|
int get_width(ScopeBase*scope) const;
|
||||||
|
|
||||||
type_t type() const { return type_; }
|
type_t type() const { return type_; }
|
||||||
|
|
||||||
|
|
@ -221,6 +227,7 @@ class VTypeArray : public VType {
|
||||||
void write_to_stream(std::ostream&fd) const;
|
void write_to_stream(std::ostream&fd) const;
|
||||||
void write_type_to_stream(std::ostream&fd) const;
|
void write_type_to_stream(std::ostream&fd) const;
|
||||||
void show(std::ostream&) const;
|
void show(std::ostream&) const;
|
||||||
|
int get_width(ScopeBase*scope) const;
|
||||||
|
|
||||||
inline size_t dimensions() const { return ranges_.size(); };
|
inline size_t dimensions() const { return ranges_.size(); };
|
||||||
const range_t&dimension(size_t idx) const
|
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 write_to_stream(std::ostream&fd) const;
|
||||||
void show(std::ostream&) const;
|
void show(std::ostream&) const;
|
||||||
|
int get_width(ScopeBase*) const { return 32; }
|
||||||
|
|
||||||
int emit_def(std::ostream&out, perm_string name) const;
|
int emit_def(std::ostream&out, perm_string name) const;
|
||||||
|
|
||||||
// Checks if the name is stored in the enum.
|
// Checks if the name is stored in the enum.
|
||||||
|
|
@ -332,10 +341,12 @@ class VTypeRecord : public VType {
|
||||||
|
|
||||||
void write_to_stream(std::ostream&fd) const;
|
void write_to_stream(std::ostream&fd) const;
|
||||||
void show(std::ostream&) const;
|
void show(std::ostream&) const;
|
||||||
|
int get_width(ScopeBase*scope) const;
|
||||||
int emit_def(std::ostream&out, perm_string name) const;
|
int emit_def(std::ostream&out, perm_string name) const;
|
||||||
|
|
||||||
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_;
|
||||||
|
|
@ -362,6 +373,7 @@ class VTypeDef : public VType {
|
||||||
|
|
||||||
void write_to_stream(std::ostream&fd) const;
|
void write_to_stream(std::ostream&fd) const;
|
||||||
void write_type_to_stream(std::ostream&fd) const;
|
void write_type_to_stream(std::ostream&fd) const;
|
||||||
|
int get_width(ScopeBase*scope) const { return type_->get_width(scope); }
|
||||||
int emit_typedef(std::ostream&out, typedef_context_t&ctx) const;
|
int emit_typedef(std::ostream&out, typedef_context_t&ctx) const;
|
||||||
|
|
||||||
int emit_def(std::ostream&out, perm_string name) const;
|
int emit_def(std::ostream&out, perm_string name) const;
|
||||||
|
|
|
||||||
|
|
@ -38,13 +38,17 @@ void VType::write_type_to_stream(ostream&fd) const
|
||||||
|
|
||||||
void VTypeArray::write_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) {
|
if (etype_ == &primitive_STDLOGIC) {
|
||||||
fd << "std_logic_vector";
|
fd << "std_logic_vector";
|
||||||
if (! ranges_.empty() && ! ranges_[0].is_box()) {
|
if (! ranges_.empty() && ! ranges_[0].is_box()) {
|
||||||
write_range_to_stream_(fd);
|
write_range_to_stream_(fd);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
} else if (etype_ == &primitive_CHARACTER &&
|
||||||
|
ranges_.size() == 1 && ranges_[0].is_box()) {
|
||||||
|
fd << "string";
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool typedefed = false;
|
bool typedefed = false;
|
||||||
|
|
|
||||||
|
|
@ -1 +1,3 @@
|
||||||
$ivlh_attribute_event vpiSysFuncSized 1 unsigned
|
$ivlh_attribute_event vpiSysFuncSized 1 unsigned
|
||||||
|
$ivlh_rising_edge vpiSysFuncSized 1 unsigned
|
||||||
|
$ivlh_falling_edge vpiSysFuncSized 1 unsigned
|
||||||
|
|
|
||||||
|
|
@ -28,14 +28,25 @@
|
||||||
* operand, and noting the time. If the $ivlh_attribute_event is
|
* operand, and noting the time. If the $ivlh_attribute_event is
|
||||||
* called at the same simulation time as a value-change, then the
|
* called at the same simulation time as a value-change, then the
|
||||||
* function returns logic true. Otherwise it returns false.
|
* 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 monitor_data {
|
||||||
struct t_vpi_time last_event;
|
struct t_vpi_time last_event;
|
||||||
|
struct t_vpi_value last_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct monitor_data **mdata = 0;
|
static struct monitor_data **mdata = 0;
|
||||||
static unsigned mdata_count = 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. */
|
/* To keep valgrind happy free the allocated memory. */
|
||||||
static PLI_INT32 cleanup_mdata(p_cb_data cause)
|
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);
|
||||||
assert(cb->time->type == vpiSimTime);
|
assert(cb->time->type == vpiSimTime);
|
||||||
|
|
||||||
mon->last_event = *(cb->time);
|
mon->last_event = *(cb->time);
|
||||||
|
mon->last_value = *(cb->value);
|
||||||
|
|
||||||
return 0;
|
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 sys = vpi_handle(vpiSysTfCall, 0);
|
||||||
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
||||||
vpiHandle arg;
|
vpiHandle arg;
|
||||||
struct monitor_data*mon;
|
struct monitor_data*mon;
|
||||||
struct t_cb_data cb;
|
struct t_cb_data cb;
|
||||||
struct t_vpi_time tb;
|
struct t_vpi_time tb;
|
||||||
|
struct t_vpi_value vb;
|
||||||
|
|
||||||
/* Check that there are arguments. */
|
/* Check that there are arguments. */
|
||||||
if (argv == 0) {
|
if (argv == 0) {
|
||||||
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys),
|
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys),
|
||||||
(int)vpi_get(vpiLineNo, sys));
|
(int)vpi_get(vpiLineNo, sys));
|
||||||
vpi_printf("(compiler error) %s requires a single argument.\n",
|
vpi_printf("(compiler error) %s requires a single argument.\n",
|
||||||
name);
|
func_names[type]);
|
||||||
vpi_control(vpiFinish, 1);
|
vpi_control(vpiFinish, 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -96,11 +111,12 @@ static PLI_INT32 ivlh_attribute_event_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
mdata[mdata_count-1] = mon;
|
mdata[mdata_count-1] = mon;
|
||||||
|
|
||||||
tb.type = vpiSimTime;
|
tb.type = vpiSimTime;
|
||||||
|
vb.format = vpiScalarVal;
|
||||||
cb.reason = cbValueChange;
|
cb.reason = cbValueChange;
|
||||||
cb.cb_rtn = monitor_events;
|
cb.cb_rtn = monitor_events;
|
||||||
cb.obj = arg;
|
cb.obj = arg;
|
||||||
cb.time = &tb;
|
cb.time = &tb;
|
||||||
cb.value = 0;
|
cb.value = &vb;
|
||||||
cb.user_data = (char*) (mon);
|
cb.user_data = (char*) (mon);
|
||||||
vpi_register_cb(&cb);
|
vpi_register_cb(&cb);
|
||||||
vpi_put_userdata(sys, mon);
|
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),
|
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys),
|
||||||
(int)vpi_get(vpiLineNo, sys));
|
(int)vpi_get(vpiLineNo, sys));
|
||||||
vpi_printf("(compiler error) %s only takes a single argument.\n",
|
vpi_printf("(compiler error) %s only takes a single argument.\n",
|
||||||
name);
|
func_names[type]);
|
||||||
vpi_free_object(argv);
|
vpi_free_object(argv);
|
||||||
vpi_control(vpiFinish, 1);
|
vpi_control(vpiFinish, 1);
|
||||||
}
|
}
|
||||||
|
|
@ -119,14 +135,13 @@ static PLI_INT32 ivlh_attribute_event_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
return 0;
|
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);
|
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
||||||
struct t_vpi_value rval;
|
struct t_vpi_value rval;
|
||||||
struct monitor_data*mon;
|
struct monitor_data*mon;
|
||||||
|
|
||||||
(void) name; /* Parameter is not used. */
|
|
||||||
|
|
||||||
rval.format = vpiScalarVal;
|
rval.format = vpiScalarVal;
|
||||||
|
|
||||||
mon = (struct monitor_data*) (vpi_get_userdata(sys));
|
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);
|
vpi_get_time(0, &tnow);
|
||||||
|
|
||||||
rval.value.scalar = vpi1;
|
rval.value.scalar = vpi1;
|
||||||
|
|
||||||
|
// Detect if there was any change
|
||||||
if (mon->last_event.high != tnow.high)
|
if (mon->last_event.high != tnow.high)
|
||||||
rval.value.scalar = vpi0;
|
rval.value.scalar = vpi0;
|
||||||
if (mon->last_event.low != tnow.low)
|
if (mon->last_event.low != tnow.low)
|
||||||
rval.value.scalar = vpi0;
|
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);
|
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;
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -168,8 +191,28 @@ static void vhdl_register(void)
|
||||||
tf_data.calltf = ivlh_attribute_event_calltf;
|
tf_data.calltf = ivlh_attribute_event_calltf;
|
||||||
tf_data.compiletf = ivlh_attribute_event_compiletf;
|
tf_data.compiletf = ivlh_attribute_event_compiletf;
|
||||||
tf_data.sizetf = ivlh_attribute_event_sizetf;
|
tf_data.sizetf = ivlh_attribute_event_sizetf;
|
||||||
tf_data.tfname = "$ivlh_attribute_event";
|
tf_data.tfname = func_names[EVENT];
|
||||||
tf_data.user_data = (PLI_BYTE8 *) "$ivlh_attribute_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);
|
res = vpi_register_systf(&tf_data);
|
||||||
vpip_make_systf_system_defined(res);
|
vpip_make_systf_system_defined(res);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue