Merge pull request #46 from orsonmmz/range
VHDL attributes: 'range, 'reverse_range, 'left & 'right
This commit is contained in:
commit
d6685f40a1
|
|
@ -567,7 +567,7 @@ const VType* ExpAttribute::probe_type(Entity*ent, Architecture*arc) const
|
||||||
{
|
{
|
||||||
base_->probe_type(ent, arc);
|
base_->probe_type(ent, arc);
|
||||||
|
|
||||||
if (name_ == "length") {
|
if (name_ == "length" || name_ == "left" || name_ == "right") {
|
||||||
return &primitive_INTEGER;
|
return &primitive_INTEGER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -313,8 +313,8 @@ int ExpAttribute::emit(ostream&out, Entity*ent, Architecture*arc)
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Special Case: The length attribute can be calculated all
|
/* Special Case: The length,left & right attributes can be calculated
|
||||||
the down to a literal integer at compile time, and all it
|
all the down to a literal integer at compile time, and all it
|
||||||
needs is the type of the base expression. (The base
|
needs is the type of the base expression. (The base
|
||||||
expression doesn't even need to be evaluated.) */
|
expression doesn't even need to be evaluated.) */
|
||||||
if (name_=="length") {
|
if (name_=="length") {
|
||||||
|
|
@ -322,9 +322,13 @@ int ExpAttribute::emit(ostream&out, Entity*ent, Architecture*arc)
|
||||||
errors += base_->emit(out, ent, arc);
|
errors += base_->emit(out, ent, arc);
|
||||||
out << ")";
|
out << ")";
|
||||||
return errors;
|
return errors;
|
||||||
|
} else if (name_=="left" || name_=="right") {
|
||||||
|
out << "$" << name_ << "(";
|
||||||
|
errors += base_->emit(out, ent, arc);
|
||||||
|
out << ")";
|
||||||
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
out << "$ivl_attribute(";
|
out << "$ivl_attribute(";
|
||||||
errors += base_->emit(out, ent, arc);
|
errors += base_->emit(out, ent, arc);
|
||||||
out << ", \"" << name_ << "\")";
|
out << ", \"" << name_ << "\")";
|
||||||
|
|
|
||||||
|
|
@ -110,8 +110,32 @@ bool ExpAttribute::evaluate(ScopeBase*, int64_t&val) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExpAttribute::evaluate(Entity*, Architecture*arc, int64_t&val) const
|
bool ExpAttribute::evaluate(Entity*ent, Architecture*arc, int64_t&val) const
|
||||||
{
|
{
|
||||||
|
if (name_ == "left" || name_ == "right") {
|
||||||
|
const VType*base_type = base_->peek_type();
|
||||||
|
if (base_type == 0)
|
||||||
|
base_type = base_->probe_type(ent,arc);
|
||||||
|
|
||||||
|
ivl_assert(*this, base_type);
|
||||||
|
|
||||||
|
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(base_type);
|
||||||
|
if (arr == 0) {
|
||||||
|
cerr << get_fileline() << ": error: "
|
||||||
|
<< "Cannot apply the 'left attribute to non-array objects"
|
||||||
|
<< endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ivl_assert(*this, arr->dimensions() == 1);
|
||||||
|
if(name_ == "left")
|
||||||
|
arr->dimension(0).msb()->evaluate(ent, arc, val);
|
||||||
|
else
|
||||||
|
arr->dimension(0).lsb()->evaluate(ent, arc, val);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return evaluate(arc, val);
|
return evaluate(arc, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -111,9 +111,10 @@ void ExpArithmetic::write_to_stream(ostream&out)
|
||||||
out << ")";
|
out << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpAttribute::write_to_stream(ostream&)
|
void ExpAttribute::write_to_stream(ostream&fd)
|
||||||
{
|
{
|
||||||
ivl_assert(*this, !"Not supported");
|
base_->write_to_stream(fd);
|
||||||
|
fd << "'" << name_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpBitstring::write_to_stream(ostream&fd)
|
void ExpBitstring::write_to_stream(ostream&fd)
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,7 @@ rem, GN_KEYWORD_2008, K_rem
|
||||||
report, GN_KEYWORD_2008, K_report
|
report, GN_KEYWORD_2008, K_report
|
||||||
restrict, GN_KEYWORD_2008, K_restrict
|
restrict, GN_KEYWORD_2008, K_restrict
|
||||||
return, GN_KEYWORD_2008, K_return
|
return, GN_KEYWORD_2008, K_return
|
||||||
|
reverse_range, GN_KEYWORD_2008, K_reverse_range
|
||||||
rol, GN_KEYWORD_2008, K_rol
|
rol, GN_KEYWORD_2008, K_rol
|
||||||
ror, GN_KEYWORD_2008, K_ror
|
ror, GN_KEYWORD_2008, K_ror
|
||||||
select, GN_KEYWORD_2008, K_select
|
select, GN_KEYWORD_2008, K_select
|
||||||
|
|
|
||||||
|
|
@ -363,7 +363,7 @@ static void import_ieee_use(ActiveScope*res, perm_string package, perm_string na
|
||||||
|
|
||||||
const VTypePrimitive primitive_BOOLEAN(VTypePrimitive::BOOLEAN, true);
|
const VTypePrimitive primitive_BOOLEAN(VTypePrimitive::BOOLEAN, true);
|
||||||
const VTypePrimitive primitive_BIT(VTypePrimitive::BIT, true);
|
const VTypePrimitive primitive_BIT(VTypePrimitive::BIT, true);
|
||||||
const VTypePrimitive primitive_INTEGER(VTypePrimitive::INTEGER, true);
|
const VTypePrimitive primitive_INTEGER(VTypePrimitive::INTEGER);
|
||||||
const VTypePrimitive primitive_REAL(VTypePrimitive::REAL);
|
const VTypePrimitive primitive_REAL(VTypePrimitive::REAL);
|
||||||
const VTypePrimitive primitive_STDLOGIC(VTypePrimitive::STDLOGIC, true);
|
const VTypePrimitive primitive_STDLOGIC(VTypePrimitive::STDLOGIC, true);
|
||||||
const VTypePrimitive primitive_CHARACTER(VTypePrimitive::CHARACTER);
|
const VTypePrimitive primitive_CHARACTER(VTypePrimitive::CHARACTER);
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,10 @@ void Package::write_to_stream(ostream&fd) const
|
||||||
continue;
|
continue;
|
||||||
if (cur->first == "std_logic_vector")
|
if (cur->first == "std_logic_vector")
|
||||||
continue;
|
continue;
|
||||||
|
if (cur->first == "signed")
|
||||||
|
continue;
|
||||||
|
if (cur->first == "unsigned")
|
||||||
|
continue;
|
||||||
|
|
||||||
fd << "type " << cur->first << " is ";
|
fd << "type " << cur->first << " is ";
|
||||||
cur->second->write_type_to_stream(fd);
|
cur->second->write_type_to_stream(fd);
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,10 @@ static ActiveScope*active_scope = new ActiveScope;
|
||||||
static stack<ActiveScope*> scope_stack;
|
static stack<ActiveScope*> scope_stack;
|
||||||
static Subprogram*active_sub = NULL;
|
static Subprogram*active_sub = NULL;
|
||||||
|
|
||||||
|
// perm_strings for attributes
|
||||||
|
const static perm_string left_attr = perm_string::literal("left");
|
||||||
|
const static perm_string right_attr = perm_string::literal("right");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When a scope boundary starts, call the push_scope function to push
|
* When a scope boundary starts, call the push_scope function to push
|
||||||
* a scope context. Preload this scope context with the contents of
|
* a scope context. Preload this scope context with the contents of
|
||||||
|
|
@ -276,7 +280,7 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
|
||||||
%token K_package K_parameter K_port K_postponed K_procedure K_process
|
%token K_package K_parameter K_port K_postponed K_procedure K_process
|
||||||
%token K_property K_protected K_pure
|
%token K_property K_protected K_pure
|
||||||
%token K_range K_record K_register K_reject K_release K_rem K_report
|
%token K_range K_record K_register K_reject K_release K_rem K_report
|
||||||
%token K_restrict K_restrict_guarantee K_return K_rol K_ror
|
%token K_restrict K_restrict_guarantee K_return K_reverse_range K_rol K_ror
|
||||||
%token K_select K_sequence K_severity K_signal K_shared
|
%token K_select K_sequence K_severity K_signal K_shared
|
||||||
%token K_sla K_sll K_sra K_srl K_strong K_subtype
|
%token K_sla K_sll K_sra K_srl K_strong K_subtype
|
||||||
%token K_then K_to K_transport K_type
|
%token K_then K_to K_transport K_type
|
||||||
|
|
@ -1904,6 +1908,34 @@ range
|
||||||
{ prange_t* tmp = new prange_t($1, $3, $2);
|
{ prange_t* tmp = new prange_t($1, $3, $2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
|
| name '\'' K_range
|
||||||
|
{
|
||||||
|
prange_t*tmp = NULL;
|
||||||
|
ExpName*name = NULL;
|
||||||
|
if((name = dynamic_cast<ExpName*>($1))) {
|
||||||
|
ExpAttribute*left = new ExpAttribute(name, left_attr);
|
||||||
|
ExpAttribute*right = new ExpAttribute(name, right_attr);
|
||||||
|
tmp = new prange_t(left, right, true);
|
||||||
|
tmp->set_auto_dir();
|
||||||
|
} else {
|
||||||
|
errormsg(@1, "'range attribute can be used with named expressions only");
|
||||||
|
}
|
||||||
|
$$ = tmp;
|
||||||
|
}
|
||||||
|
| name '\'' K_reverse_range
|
||||||
|
{
|
||||||
|
prange_t*tmp = NULL;
|
||||||
|
ExpName*name = NULL;
|
||||||
|
if((name = dynamic_cast<ExpName*>($1))) {
|
||||||
|
ExpAttribute*left = new ExpAttribute(name, left_attr);
|
||||||
|
ExpAttribute*right = new ExpAttribute(name, right_attr);
|
||||||
|
tmp = new prange_t(left, right, false);
|
||||||
|
tmp->set_auto_dir();
|
||||||
|
} else {
|
||||||
|
errormsg(@1, "'reverse_range attribute can be used with named expressions only");
|
||||||
|
}
|
||||||
|
$$ = tmp;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
range_list
|
range_list
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ class instant_list_t {
|
||||||
class prange_t {
|
class prange_t {
|
||||||
public:
|
public:
|
||||||
prange_t(Expression* left, Expression* right, bool dir)
|
prange_t(Expression* left, Expression* right, bool dir)
|
||||||
: left_(left), right_(right), direction_(dir) {}
|
: left_(left), right_(right), direction_(dir), auto_dir_(false) {}
|
||||||
~prange_t() { delete left_; delete right_; }
|
~prange_t() { delete left_; delete right_; }
|
||||||
void dump(ostream&out, int indent) const;
|
void dump(ostream&out, int indent) const;
|
||||||
|
|
||||||
|
|
@ -79,12 +79,16 @@ class prange_t {
|
||||||
inline Expression*lsb() { return direction_? right_: left_; }
|
inline Expression*lsb() { return direction_? right_: left_; }
|
||||||
|
|
||||||
inline bool is_downto() const { return direction_; }
|
inline bool is_downto() const { return direction_; }
|
||||||
|
inline void set_auto_dir(bool enabled = true) { auto_dir_ = enabled; };
|
||||||
|
inline bool is_auto_dir() const { return auto_dir_; }
|
||||||
|
|
||||||
inline Expression*expr_left() { return left_; }
|
inline Expression*expr_left() { return left_; }
|
||||||
inline Expression*expr_right() { return right_; }
|
inline Expression*expr_right() { return right_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Expression *left_, *right_;
|
Expression *left_, *right_;
|
||||||
bool direction_;
|
bool direction_;
|
||||||
|
bool auto_dir_;
|
||||||
|
|
||||||
private: //not implemented
|
private: //not implemented
|
||||||
prange_t(const prange_t&);
|
prange_t(const prange_t&);
|
||||||
|
|
|
||||||
|
|
@ -212,24 +212,34 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, Architecture*arc)
|
||||||
ivl_assert(*this, start_rc);
|
ivl_assert(*this, start_rc);
|
||||||
ivl_assert(*this, finish_rc);
|
ivl_assert(*this, finish_rc);
|
||||||
|
|
||||||
if (! range_->is_downto()) {
|
bool dir = range_->is_downto();
|
||||||
|
|
||||||
|
if (!dir) {
|
||||||
int64_t tmp = start_val;
|
int64_t tmp = start_val;
|
||||||
start_val = finish_val;
|
start_val = finish_val;
|
||||||
finish_val = tmp;
|
finish_val = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (range_->is_downto() && (start_val < finish_val)) {
|
if (dir && (start_val < finish_val)) {
|
||||||
out << "begin /* Degenerate loop at " << get_fileline()
|
if(range_->is_auto_dir()) {
|
||||||
<< ": " << start_val
|
dir = false;
|
||||||
<< " downto " << finish_val << " */ end" << endl;
|
} else {
|
||||||
return errors;
|
out << "begin /* Degenerate loop at " << get_fileline()
|
||||||
|
<< ": " << start_val
|
||||||
|
<< " downto " << finish_val << " */ end" << endl;
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!range_->is_downto() && start_val > finish_val) {
|
else if (!dir && start_val > finish_val) {
|
||||||
out << "begin /* Degenerate loop at " << get_fileline()
|
if(range_->is_auto_dir()) {
|
||||||
<< ": " << start_val
|
dir = true;
|
||||||
<< " to " << finish_val << " */ end" << endl;
|
} else {
|
||||||
return errors;
|
out << "begin /* Degenerate loop at " << get_fileline()
|
||||||
|
<< ": " << start_val
|
||||||
|
<< " to " << finish_val << " */ end" << endl;
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
perm_string scope_name = loop_name();
|
perm_string scope_name = loop_name();
|
||||||
|
|
@ -242,12 +252,12 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, Architecture*arc)
|
||||||
out << "begin : " << scope_name << endl;
|
out << "begin : " << scope_name << endl;
|
||||||
out << "longint \\" << it_ << " ;" << endl;
|
out << "longint \\" << it_ << " ;" << endl;
|
||||||
out << "for (\\" << it_ << " = " << start_val << " ; ";
|
out << "for (\\" << it_ << " = " << start_val << " ; ";
|
||||||
if (range_->is_downto())
|
if (dir)
|
||||||
out << "\\" << it_ << " >= " << finish_val;
|
out << "\\" << it_ << " >= " << finish_val;
|
||||||
else
|
else
|
||||||
out << "\\" << it_ << " <= " << finish_val;
|
out << "\\" << it_ << " <= " << finish_val;
|
||||||
out << "; \\" << it_ << " = \\" << it_;
|
out << "; \\" << it_ << " = \\" << it_;
|
||||||
if (range_->is_downto())
|
if (dir)
|
||||||
out << " - 1";
|
out << " - 1";
|
||||||
else
|
else
|
||||||
out << " + 1";
|
out << " + 1";
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ int Subprogram::emit_package(ostream&fd) const
|
||||||
if (statements_) {
|
if (statements_) {
|
||||||
for (list<SequentialStmt*>::const_iterator cur = statements_->begin()
|
for (list<SequentialStmt*>::const_iterator cur = statements_->begin()
|
||||||
; cur != statements_->end() ; ++cur) {
|
; cur != statements_->end() ; ++cur) {
|
||||||
errors += (*cur)->emit(fd, 0, 0);
|
errors += (*cur)->emit(fd, NULL, NULL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fd << " begin /* empty body */ end" << endl;
|
fd << " begin /* empty body */ end" << endl;
|
||||||
|
|
|
||||||
|
|
@ -195,6 +195,7 @@ class VTypeArray : public VType {
|
||||||
|
|
||||||
int elaborate(Entity*ent, Architecture*arc) const;
|
int elaborate(Entity*ent, Architecture*arc) const;
|
||||||
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 show(std::ostream&) const;
|
void show(std::ostream&) const;
|
||||||
|
|
||||||
inline size_t dimensions() const { return ranges_.size(); };
|
inline size_t dimensions() const { return ranges_.size(); };
|
||||||
|
|
@ -312,7 +313,7 @@ class VTypeDef : public VType {
|
||||||
inline const VType* peek_definition(void) const { return type_; }
|
inline const VType* peek_definition(void) const { return type_; }
|
||||||
|
|
||||||
void write_to_stream(std::ostream&fd) const;
|
void write_to_stream(std::ostream&fd) const;
|
||||||
void write_type_to_stream(ostream&fd) const;
|
void write_type_to_stream(std::ostream&fd) const;
|
||||||
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;
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@ int VTypePrimitive::emit_primitive_type(ostream&out) const
|
||||||
out << "logic";
|
out << "logic";
|
||||||
break;
|
break;
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
out << "bool[31:0]";
|
out << "int";
|
||||||
break;
|
break;
|
||||||
case REAL:
|
case REAL:
|
||||||
out << "real";
|
out << "real";
|
||||||
|
|
|
||||||
|
|
@ -90,9 +90,40 @@ void VTypeArray::write_range_to_stream_(std::ostream&fd) const
|
||||||
fd << ") ";
|
fd << ") ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VTypeArray::write_type_to_stream(ostream&fd) const
|
||||||
|
{
|
||||||
|
// Special case: std_logic_vector
|
||||||
|
if (etype_ == &primitive_STDLOGIC) {
|
||||||
|
fd << "std_logic_vector";
|
||||||
|
if (! ranges_.empty() && ! ranges_[0].is_box()) {
|
||||||
|
write_range_to_stream_(fd);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd << "array ";
|
||||||
|
|
||||||
|
if (! ranges_.empty()) {
|
||||||
|
assert(ranges_.size() < 2);
|
||||||
|
if (ranges_[0].is_box()) {
|
||||||
|
fd << "(INTEGER range <>) ";
|
||||||
|
} else {
|
||||||
|
write_range_to_stream_(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fd << "of ";
|
||||||
|
|
||||||
|
if(const VTypeDef*tdef = dynamic_cast<const VTypeDef*>(etype_)) {
|
||||||
|
tdef->write_to_stream(fd);
|
||||||
|
} else {
|
||||||
|
etype_->write_to_stream(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void VTypeDef::write_type_to_stream(ostream&fd) const
|
void VTypeDef::write_type_to_stream(ostream&fd) const
|
||||||
{
|
{
|
||||||
type_->write_to_stream(fd);
|
type_->write_type_to_stream(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VTypeDef::write_to_stream(ostream&fd) const
|
void VTypeDef::write_to_stream(ostream&fd) const
|
||||||
|
|
|
||||||
|
|
@ -808,6 +808,10 @@ statement
|
||||||
symbols_net ';'
|
symbols_net ';'
|
||||||
{ compile_netw($1, $3, $4, $6, $7, vpiLogicVar, true, $9.cnt, $9.vect); }
|
{ compile_netw($1, $3, $4, $6, $7, vpiLogicVar, true, $9.cnt, $9.vect); }
|
||||||
|
|
||||||
|
| T_LABEL K_NET_2S T_SYMBOL T_NUMBER ',' signed_t_number signed_t_number ','
|
||||||
|
symbols_net ';'
|
||||||
|
{ compile_netw($1, $3, $4, $6, $7, vpiIntVar, true, $9.cnt, $9.vect); }
|
||||||
|
|
||||||
| T_LABEL K_NET8 T_SYMBOL T_NUMBER ',' signed_t_number signed_t_number ','
|
| T_LABEL K_NET8 T_SYMBOL T_NUMBER ',' signed_t_number signed_t_number ','
|
||||||
symbols_net ';'
|
symbols_net ';'
|
||||||
{ compile_netw($1, $3, $4, $6, $7, -vpiLogicVar, false, $9.cnt, $9.vect); }
|
{ compile_netw($1, $3, $4, $6, $7, -vpiLogicVar, false, $9.cnt, $9.vect); }
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue