From 88cce86c638047d413c1a392ad770570d7ab50a8 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 18 Sep 2011 19:31:28 -0700 Subject: [PATCH] Emit code for the to_unsigned() bulit-in function. --- vhdlpp/expression.cc | 55 +++++++++++++++++++++++++++++++++++---- vhdlpp/expression.h | 10 +++++-- vhdlpp/expression_emit.cc | 9 +++++++ vhdlpp/parse.y | 17 ++++++++++-- 4 files changed, 82 insertions(+), 9 deletions(-) diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index c5c4e6521..be69247ac 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -22,6 +22,7 @@ # include # include # include +# include # include using namespace std; @@ -86,6 +87,40 @@ ExpAttribute::~ExpAttribute() delete base_; } +bool ExpAttribute::evaluate(ScopeBase*, int64_t&val) const +{ + /* Special Case: The length attribute can be calculated all + the down to a literal integer at compile time, and all it + needs is the type of the base expression. (The base + expression doesn't even need to be evaluated.) */ + if (name_ == "length") { + 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(base_type); + if (arr == 0) { + cerr << get_fileline() << ": error: " + << "Cannot apply the 'length attribute to non-array objects" + << endl; + return false; + } + + int64_t size = 1; + for (size_t idx = 0 ; idx < arr->dimensions() ; idx += 1) { + const VTypeArray::range_t&dim = arr->dimension(idx); + ivl_assert(*this, ! dim.is_box()); + size *= 1 + labs(dim.msb() - dim.lsb()); + } + val = size; + return true; + } + + return false; +} + ExpBinary::ExpBinary(Expression*op1, Expression*op2) : operand1_(op1), operand2_(op2) { @@ -296,10 +331,15 @@ ExpFunc::ExpFunc(perm_string nn) { } -ExpFunc::ExpFunc(perm_string nn, Expression*arg) -: name_(nn), argv_(1) +ExpFunc::ExpFunc(perm_string nn, list*args) +: name_(nn), argv_(args->size()) { - argv_[0] = arg; + for (size_t idx = 0; idx < argv_.size() ; idx += 1) { + ivl_assert(*this, !args->empty()); + argv_[idx] = args->front(); + args->pop_front(); + } + ivl_assert(*this, args->empty()); } ExpFunc::~ExpFunc() @@ -337,9 +377,14 @@ ExpName::ExpName(perm_string nn) { } -ExpName::ExpName(perm_string nn, Expression*ix) -: name_(nn), index_(ix), lsb_(0) +ExpName::ExpName(perm_string nn, list*indices) +: name_(nn), index_(0), lsb_(0) { + /* For now, assume a single index. */ + ivl_assert(*this, indices->size() == 1); + + index_ = indices->front(); + indices->pop_front(); } ExpName::ExpName(perm_string nn, Expression*msb, Expression*lsb) diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index 094ffd36b..d9cdea674 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -96,6 +96,9 @@ class Expression : public LineInfo { virtual void dump(ostream&out, int indent = 0) const =0; protected: + // This function is called by the derived class during + // elaboration to set the type of the current expression that + // elaboration assigns to this expression. void set_type(const VType*); private: @@ -258,8 +261,11 @@ class ExpAttribute : public Expression { inline perm_string peek_attribute() const { return name_; } inline const ExpName* peek_base() const { return base_; } + const VType*probe_type(Entity*ent, Architecture*arc) const; int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); int emit(ostream&out, Entity*ent, Architecture*arc); + // Some attributes can be evaluated at compile time + bool evaluate(ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; private: @@ -351,7 +357,7 @@ class ExpFunc : public Expression { public: explicit ExpFunc(perm_string nn); - ExpFunc(perm_string nn, Expression*arg); + ExpFunc(perm_string nn, std::list*args); ~ExpFunc(); public: // Base methods @@ -409,7 +415,7 @@ class ExpName : public Expression { public: explicit ExpName(perm_string nn); - ExpName(perm_string nn, Expression*index); + ExpName(perm_string nn, std::list*indices); ExpName(perm_string nn, Expression*msb, Expression*lsb); ~ExpName(); diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index fcf7a9af0..02dc5fae3 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -354,6 +354,15 @@ int ExpFunc::emit(ostream&out, Entity*ent, Architecture*arc) errors += argv_[0]->emit(out, ent, arc); out << ")"; + } else if (name_ == "to_unsigned" && argv_.size() == 2) { + int64_t use_size; + bool rc = argv_[1]->evaluate(arc, use_size); + ivl_assert(*this, rc); + + out << "$unsigned(" << use_size << "'("; + errors += argv_[0]->emit(out, ent, arc); + out << "))"; + } else { out << "\\" << name_ << " ("; for (size_t idx = 0; idx < argv_.size() ; idx += 1) { diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 996ecb03e..d44dd43d2 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -248,7 +248,7 @@ const VType*parse_type_by_name(perm_string name) %type shift_expression simple_expression term waveform_element %type waveform waveform_elements -%type name_list +%type name_list expression_list %type process_sensitivity_list process_sensitivity_list_opt %type association_element @@ -781,6 +781,19 @@ entity_header { $$ = $1; } ; +expression_list + : expression_list ',' expression + { list*tmp = $1; + tmp->push_back($3); + $$ = tmp; + } + | expression + { list*tmp = new list; + tmp->push_back($1); + $$ = tmp; + } + ; + expression : expression_logical { $$ = $1; } @@ -1171,7 +1184,7 @@ name function calls. The only way we can tell the difference is from left context, namely whether the name is a type name or function name. If none of the above, treat it as a array element select. */ - | IDENTIFIER '(' expression ')' + | IDENTIFIER '(' expression_list ')' { perm_string name = lex_strings.make($1); delete[]$1; if (active_scope->is_vector_name(name)) {