commit
437dc10341
|
|
@ -28,7 +28,7 @@ using namespace std;
|
|||
|
||||
Architecture::Architecture(perm_string name, const ActiveScope&ref,
|
||||
list<Architecture::Statement*>&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<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)
|
||||
{
|
||||
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,
|
||||
std::list<Expression*>*sensitivity_list,
|
||||
std::list<SequentialStmt*>*statements_list)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
# include <list>
|
||||
# include <map>
|
||||
|
||||
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_t> 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_;
|
||||
|
|
|
|||
|
|
@ -92,6 +92,8 @@ int ComponentInstantiation::elaborate(Entity*ent, Architecture*arc)
|
|||
return 1;
|
||||
}
|
||||
|
||||
arc->set_cur_component(this);
|
||||
|
||||
for (map<perm_string,Expression*>::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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -92,7 +92,8 @@ int Entity::elaborate_generic_exprs_()
|
|||
for (vector<InterfacePort*>::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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 << ") ";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<InterfacePort*>::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<InterfacePort*>::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<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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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,6 +661,22 @@ class ExpName : public Expression {
|
|||
|
||||
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:
|
||||
std::auto_ptr<ExpName> prefix_;
|
||||
perm_string name_;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -922,87 +928,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<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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -306,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);
|
||||
|
|
@ -552,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
|
||||
|
|
@ -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 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);
|
||||
|
|
@ -736,6 +752,121 @@ int ExpName::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
|||
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
|
||||
{
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -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") {
|
||||
|
|
@ -191,8 +182,10 @@ bool ExpName::evaluate(ScopeBase*scope, int64_t&val) const
|
|||
return false;
|
||||
}
|
||||
|
||||
bool rc = scope->find_constant(name_, type, exp);
|
||||
if (rc == false)
|
||||
if (!scope)
|
||||
return false;
|
||||
|
||||
if (!scope->find_constant(name_, type, exp))
|
||||
return false;
|
||||
|
||||
return exp->evaluate(scope, val);
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
return new VTypeArray::range_t(safe_clone(msb_), safe_clone(lsb_), direction_);
|
||||
|
|
@ -176,6 +195,30 @@ void VTypeArray::show(ostream&out) const
|
|||
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 {
|
||||
for(std::vector<range_t>::const_iterator it = ranges_.begin();
|
||||
it != ranges_.end(); ++it)
|
||||
|
|
@ -281,6 +324,23 @@ void VTypeRecord::show(ostream&out) const
|
|||
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
|
||||
{
|
||||
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
|
||||
// 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 <name> 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(ScopeBase*) 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(ScopeBase*scope) 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(ScopeBase*scope) 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(ScopeBase*) const { return 32; }
|
||||
|
||||
int emit_def(std::ostream&out, perm_string name) const;
|
||||
|
||||
// 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 show(std::ostream&) const;
|
||||
int get_width(ScopeBase*scope) const;
|
||||
int emit_def(std::ostream&out, perm_string name) const;
|
||||
|
||||
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_;
|
||||
|
|
@ -362,6 +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(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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1 +1,3 @@
|
|||
$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
|
||||
* 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);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue