Merge pull request #55 from orsonmmz/const_record

Const record
This commit is contained in:
Stephen Williams 2015-03-12 10:30:56 -07:00
commit 437dc10341
19 changed files with 466 additions and 152 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 << ") ";
}

View File

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

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2012-2014 / Stephen Williams (steve@icarus.com),
* Copyright CERN 2012-2015 / Stephen Williams (steve@icarus.com),
* Maciej Suminski (maciej.suminski@cern.ch)
*
* This source code is free software; you can redistribute it
@ -450,11 +450,6 @@ ExpName::~ExpName()
delete index_;
}
const char* ExpName::name() const
{
return name_;
}
bool ExpName::symbolic_compare(const Expression*that) const
{
const ExpName*that_name = dynamic_cast<const ExpName*> (that);
@ -485,6 +480,28 @@ void ExpName::set_range(Expression*msb, Expression*lsb)
lsb_ = lsb;
}
int ExpName::index_t::emit(ostream&out, Entity*ent, ScopeBase*scope)
{
int errors = 0;
out << "(";
if(idx_ && size_) {
errors += idx_->emit(out, ent, scope);
out << "*";
errors += size_->emit(out, ent, scope);
}
if(offset_) {
if(idx_ && size_)
out << "+";
errors += offset_->emit(out, ent, scope);
}
out << ")";
return errors;
}
ExpRelation::ExpRelation(ExpRelation::fun_t ty, Expression*op1, Expression*op2)
: ExpBinary(op1, op2), fun_(ty)
{

View File

@ -2,7 +2,7 @@
#define IVL_expression_H
/*
* Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com)
* Copyright CERN 2014 / Stephen Williams (steve@icarus.com),
* Copyright CERN 2015 / Stephen Williams (steve@icarus.com),
* Maciej Suminski (maciej.suminski@cern.ch)
*
* This source code is free software; you can redistribute it
@ -105,7 +105,6 @@ class Expression : public LineInfo {
virtual bool evaluate(ScopeBase*scope, int64_t&val) const;
virtual bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
// The symbolic compare returns true if the two expressions
// are equal without actually calculating the value.
virtual bool symbolic_compare(const Expression*that) const;
@ -635,12 +634,25 @@ class ExpName : public Expression {
bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
bool symbolic_compare(const Expression*that) const;
void dump(ostream&out, int indent = 0) const;
const char* name() const;
inline const char* name() const { return name_; }
inline const perm_string& peek_name() const { return name_; }
void set_range(Expression*msb, Expression*lsb);
private:
class index_t {
public:
index_t(Expression*idx, Expression*size, Expression*offset = NULL) :
idx_(idx), size_(size), offset_(offset) {}
int emit(ostream&out, Entity*ent, ScopeBase*scope);
private:
Expression*idx_;
Expression*size_;
Expression*offset_;
};
const VType* elaborate_adjust_type_with_range_(Entity*ent, ScopeBase*scope, const VType*type);
int elaborate_lval_(Entity*ent, ScopeBase*scope, bool, ExpName*suffix);
@ -649,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_;

View File

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

View File

@ -1,6 +1,7 @@
/*
* Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com)
* Copyright CERN 2012-2015 / Stephen Williams (steve@icarus.com)
* Maciej Suminski (maciej.suminski@cern.ch)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -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;

View File

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

View File

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

View File

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

View File

@ -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()

View File

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

View File

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

View File

@ -1 +1,3 @@
$ivlh_attribute_event vpiSysFuncSized 1 unsigned
$ivlh_rising_edge vpiSysFuncSized 1 unsigned
$ivlh_falling_edge vpiSysFuncSized 1 unsigned

View File

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