diff --git a/PExpr.h b/PExpr.h index 34168da4d..55f0fb237 100644 --- a/PExpr.h +++ b/PExpr.h @@ -999,6 +999,9 @@ class PECastType : public PExpr { void dump(ostream &out) const; + virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, + ivl_type_t type, unsigned flags) const; + virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, unsigned expr_wid, unsigned flags) const; diff --git a/elab_expr.cc b/elab_expr.cc index 367093a30..d36ae1eb5 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -2536,11 +2536,44 @@ unsigned PECastType::test_width(Design*des, NetScope*scope, width_mode_t&wid) expr_width_ = t->packed_width(); } - signed_flag_= t->get_signed(); + signed_flag_ = t->get_signed(); min_width_ = expr_width_; return expr_width_; } +NetExpr* PECastType::elaborate_expr(Design*des, NetScope*scope, + ivl_type_t type, unsigned) const +{ + const netdarray_t*darray = NULL; + const netvector_t*vector = NULL; + + // Casting array of vectors to dynamic array type + if((darray = dynamic_cast(type)) && + (vector = dynamic_cast(darray->element_type()))) { + PExpr::width_mode_t mode = PExpr::SIZED; + unsigned use_wid = base_->test_width(des, scope, mode); + NetExpr*base = base_->elaborate_expr(des, scope, use_wid, NO_FLAGS); + + assert(vector->packed_width() > 0); + assert(base->expr_width() > 0); + + // Find rounded up length that can fit the whole casted array of vectors + int len = base->expr_width() + vector->packed_width() - 1; + if(base->expr_width() > vector->packed_width()) { + len /= vector->packed_width(); + } else { + len /= base->expr_width(); + } + + // Number of words in the created dynamic array + NetEConst*len_expr = new NetEConst(verinum(len)); + return new NetENew(type, len_expr, base); + } + + // Fallback + return elaborate_expr(des, scope, (unsigned) 0, 0); +} + NetExpr* PECastType::elaborate_expr(Design*des, NetScope*scope, unsigned, unsigned) const { diff --git a/pform.cc b/pform.cc index b8318c792..c0ad24fd9 100644 --- a/pform.cc +++ b/pform.cc @@ -2661,7 +2661,6 @@ vector*pform_make_task_ports(const struct vlltype&loc, } delete range; - delete names; return res; } @@ -2690,7 +2689,6 @@ static vector*do_make_task_ports(const struct vlltype&loc, res->push_back(pform_tf_port_t(curw)); } - delete names; return res; } @@ -2699,35 +2697,54 @@ vector*pform_make_task_ports(const struct vlltype&loc, data_type_t*vtype, list*names) { + vector*ret = NULL; + std::list*unpacked_dims = NULL; + + if (uarray_type_t*uarray = dynamic_cast (vtype)) { + unpacked_dims = uarray->dims.get(); + vtype = uarray->base_type; + } + if (atom2_type_t*atype = dynamic_cast (vtype)) { list*range_tmp = make_range_from_width(atype->type_code); - return pform_make_task_ports(loc, pt, IVL_VT_BOOL, + ret = pform_make_task_ports(loc, pt, IVL_VT_BOOL, atype->signed_flag, range_tmp, names); } if (vector_type_t*vec_type = dynamic_cast (vtype)) { - return pform_make_task_ports(loc, pt, vec_type->base_type, + ret = pform_make_task_ports(loc, pt, vec_type->base_type, vec_type->signed_flag, copy_range(vec_type->pdims.get()), names, vec_type->integer_flag); } if (/*real_type_t*real_type = */ dynamic_cast (vtype)) { - return pform_make_task_ports(loc, pt, IVL_VT_REAL, + ret = pform_make_task_ports(loc, pt, IVL_VT_REAL, true, 0, names); } if (dynamic_cast (vtype)) { - return pform_make_task_ports(loc, pt, IVL_VT_STRING, + ret = pform_make_task_ports(loc, pt, IVL_VT_STRING, false, 0, names); } if (class_type_t*class_type = dynamic_cast (vtype)) { - return do_make_task_ports(loc, pt, IVL_VT_CLASS, class_type, names); + ret = do_make_task_ports(loc, pt, IVL_VT_CLASS, class_type, names); } - return do_make_task_ports(loc, pt, IVL_VT_NO_TYPE, vtype, names); + ret = do_make_task_ports(loc, pt, IVL_VT_NO_TYPE, vtype, names); + + if (unpacked_dims) { + for (list::iterator cur = names->begin() + ; cur != names->end() ; ++ cur ) { + PWire*wire = pform_get_wire_in_scope(*cur); + wire->set_unpacked_idx(*unpacked_dims); + } + } + + delete names; + return ret; } /* diff --git a/tgt-vvp/eval_object.c b/tgt-vvp/eval_object.c index 2ce9868c9..3c03c188d 100644 --- a/tgt-vvp/eval_object.c +++ b/tgt-vvp/eval_object.c @@ -129,12 +129,15 @@ static int eval_darray_new(ivl_expr_t ex) unsigned wid; switch (ivl_type_base(element_type)) { case IVL_VT_BOOL: + case IVL_VT_LOGIC: wid = width_of_packed_type(element_type); - draw_eval_vec4(init_expr); - resize_vec4_wid(init_expr, wid); for (idx = 0 ; idx < cnt ; idx += 1) { - fprintf(vvp_out, " %%ix/load 3, %ld, 0;\n", idx); + draw_eval_vec4(init_expr); + fprintf(vvp_out, " %%parti/%c %d, %ld, 6;\n", + ivl_expr_signed(init_expr) ? 's' : 'u', wid, idx * wid); + fprintf(vvp_out, " %%ix/load 3, %ld, 0;\n", cnt - idx - 1); fprintf(vvp_out, " %%set/dar/obj/vec4 3;\n"); + fprintf(vvp_out, " %%pop/vec4 1;\n"); } break; case IVL_VT_REAL: diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index 779104510..e2456ae25 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -444,7 +444,7 @@ static int show_stmt_assign_vector(ivl_statement_t net) fprintf(vvp_out, " %%cvt/vr %u;\n", wid); } else if (ivl_expr_value(rval) == IVL_VT_STRING) { - /* Special case: vector to string casting */ + /* Special case: string to vector casting */ ivl_lval_t lval = ivl_stmt_lval(net, 0); fprintf(vvp_out, " %%vpi_call %u %u \"$ivl_string_method$to_vec\", v%p_0, v%p_0 {0 0 0};\n", ivl_file_table_index(ivl_stmt_file(net)), ivl_stmt_lineno(net), @@ -452,6 +452,28 @@ static int show_stmt_assign_vector(ivl_statement_t net) if (slices) free(slices); return 0; + } else if (ivl_expr_value(rval) == IVL_VT_DARRAY) { + /* Special case: dynamic array to vector casting */ + ivl_lval_t lval = ivl_stmt_lval(net, 0); + void*rval_addr = NULL; + + /* Even more special case: function call returning dynamic array */ + if(ivl_expr_type(rval) == IVL_EX_UFUNC) { + rval_addr = ivl_scope_port(ivl_expr_def(rval), 0); + draw_ufunc_object(rval); + /* We do not need to store the result, it is going to be + converted to vector quite soon. */ + fprintf(vvp_out, " %%pop/obj 1, 0; drop the result\n"); + } else { + rval_addr = ivl_expr_signal(rval); + } + + fprintf(vvp_out, " %%vpi_call %u %u \"$ivl_darray_method$to_vec\", v%p_0, v%p_0 {0 0 0};\n", + ivl_file_table_index(ivl_stmt_file(net)), ivl_stmt_lineno(net), + rval_addr, ivl_lval_sig(lval)); + if (slices) free(slices); + return 0; + } else { unsigned wid = ivl_stmt_lwidth(net); draw_eval_vec4(rval); diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index c255df43a..62a368813 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -368,9 +368,11 @@ int SignalAssignment::elaborate(Entity*ent, Architecture*arc) return errors; } - for (list::const_iterator cur = rval_.begin() + for (list::iterator cur = rval_.begin() ; cur != rval_.end() ; ++cur) { (*cur)->elaborate_expr(ent, arc, lval_type); + + // Handle functions that return unbounded arrays } return errors; diff --git a/vhdlpp/architec_emit.cc b/vhdlpp/architec_emit.cc index ef17e370a..c344564e0 100644 --- a/vhdlpp/architec_emit.cc +++ b/vhdlpp/architec_emit.cc @@ -103,7 +103,9 @@ int Architecture::emit(ostream&out, Entity*entity) for (map::const_iterator cur = cur_subprograms_.begin() ; cur != cur_subprograms_.end() ; ++ cur) { - errors += cur->second->emit_package(out); + // Do not emit unbounded functions, we will just need fixed instances later + if(!cur->second->unbounded()) + errors += cur->second->emit_package(out); } for (list::iterator cur = statements_.begin() diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index feeddd88e..e8c71ee12 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -20,6 +20,7 @@ */ # include "expression.h" +# include "subprogram.h" # include "parse_types.h" # include "scope.h" # include @@ -63,6 +64,11 @@ ExpAttribute::~ExpAttribute() delete base_; } +Expression*ExpAttribute::clone() const +{ + return new ExpAttribute(static_cast(base_->clone()), name_); +} + ExpBinary::ExpBinary(Expression*op1, Expression*op2) : operand1_(op1), operand2_(op2) { @@ -112,6 +118,23 @@ ExpAggregate::~ExpAggregate() delete elements_[idx]; } +Expression* ExpAggregate::clone() const +{ + std::list*new_elements = NULL; + + if(!elements_.empty()) { + new_elements = new std::list(); + for(std::vector::const_iterator it = elements_.begin(); + it != elements_.end(); ++it) { + new_elements->push_back(new element_t(**it)); + } + } + + assert(aggregate_.empty()); // cloning should not happen after elab + + return new ExpAggregate(new_elements); +} + ExpAggregate::choice_t::choice_t(Expression*exp) : expr_(exp) { @@ -126,6 +149,15 @@ ExpAggregate::choice_t::choice_t(prange_t*rang) { } +ExpAggregate::choice_t::choice_t(const choice_t&other) +{ + if(Expression*e = other.expr_.get()) + expr_.reset(e->clone()); + + if(other.range_.get()) + range_.reset(new prange_t(*other.range_.get())); +} + ExpAggregate::choice_t::~choice_t() { } @@ -159,6 +191,18 @@ ExpAggregate::element_t::element_t(list*fields, Expression*val) } } +ExpAggregate::element_t::element_t(const ExpAggregate::element_t&other) +{ + fields_.reserve(other.fields_.size()); + + for(std::vector::const_iterator it = other.fields_.begin(); + it != other.fields_.end(); ++it) { + fields_.push_back(*it); + } + + val_ = other.val_->clone(); +} + ExpAggregate::element_t::~element_t() { for (size_t idx = 0 ; idx < fields_.size() ; idx += 1) @@ -235,12 +279,46 @@ ExpConditional::~ExpConditional() } } +Expression*ExpConditional::clone() const +{ + std::list*new_true_clause = NULL; + if(!true_clause_.empty()) { + new_true_clause = new std::list(); + + for(std::list::const_iterator it = true_clause_.begin(); + it != true_clause_.end(); ++it) { + new_true_clause->push_back((*it)->clone()); + } + } + + std::list*new_else_clause = NULL; + if(!else_clause_.empty()) { + new_else_clause = new std::list(); + + for(std::list::const_iterator it = else_clause_.begin(); + it != else_clause_.end(); ++it) { + new_else_clause->push_back(new else_t(**it)); + } + } + + return new ExpConditional(cond_->clone(), new_true_clause, new_else_clause); +} + ExpConditional::else_t::else_t(Expression*cond, std::list*tru) : cond_(cond) { if (tru) true_clause_.splice(true_clause_.end(), *tru); } +ExpConditional::else_t::else_t(const else_t&other) +{ + cond_ = other.cond_->clone(); + for(std::list::const_iterator it = other.true_clause_.begin(); + it != other.true_clause_.end(); ++it) { + true_clause_.push_back((*it)->clone()); + } +} + ExpConditional::else_t::~else_t() { delete cond_; @@ -283,6 +361,27 @@ ExpFunc::~ExpFunc() delete argv_[idx]; } +Expression*ExpFunc::clone() const { + std::list*new_args = NULL; + + if(!argv_.empty()) { + new_args = new std::list(); + for(std::vector::const_iterator it = argv_.begin(); + it != argv_.end(); ++it) + new_args->push_back((*it)->clone()); + } + + ExpFunc*f = new ExpFunc(name_, new_args); + f->def_ = def_; + + return f; +} + +const VType* ExpFunc::func_ret_type() const +{ + return def_ ? def_->peek_return_type() : NULL; +} + ExpInteger::ExpInteger(int64_t val) : value_(val) { @@ -423,3 +522,22 @@ ExpUNot::ExpUNot(Expression*op1) ExpUNot::~ExpUNot() { } + +ExpCast::ExpCast(Expression*base, const VType*type) : + base_(base), type_(type) +{ +} + +ExpCast::~ExpCast() +{ +} + +ExpNew::ExpNew(Expression*size) : + size_(size) +{ +} + +ExpNew::~ExpNew() +{ + delete size_; +} diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index b791f9a21..058533f86 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -31,13 +31,11 @@ class prange_t; class Entity; -class Architecture; class ScopeBase; class Subprogram; class VType; class VTypeArray; class VTypePrimitive; - class ExpName; /* @@ -51,18 +49,21 @@ class Expression : public LineInfo { Expression(); virtual ~Expression() =0; + // Returns a deep copy of the expression. + virtual Expression*clone() const =0; + // This virtual method handles the special case of elaborating // an expression that is the l-value of a sequential variable // assignment. This generates an error for most cases, but // expressions that are valid l-values return 0 and set any // flags needed to indicate their status as writable variables. - virtual int elaborate_lval(Entity*ent, Architecture*arc, + virtual int elaborate_lval(Entity*ent, ScopeBase*scope, bool is_sequ); // This virtual method probes the expression to get the most // constrained type for the expression. For a given instance, // this may be called before the elaborate_expr method. - virtual const VType*probe_type(Entity*ent, Architecture*arc) const; + virtual const VType*probe_type(Entity*ent, ScopeBase*scope) const; // The fit_type virtual method is used by the ExpConcat class // to probe the type of operands. The atype argument is the @@ -70,13 +71,13 @@ class Expression : public LineInfo { // returns its type as interpreted in this context. Really, // this is mostly about helping aggregate expressions within // concatenations to figure out their type. - virtual const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const; + virtual const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const; // This virtual method elaborates an expression. The ltype is // the type of the lvalue expression, if known, and can be // used to calculate the type for the expression being // elaborated. - virtual int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); + virtual int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); // Return the type that this expression would be if it were an // l-value. This should only be called after elaborate_lval is @@ -86,12 +87,12 @@ class Expression : public LineInfo { // This virtual method writes a VHDL-accurate representation // of this expression to the designated stream. This is used // for writing parsed types to library files. - virtual void write_to_stream(std::ostream&fd) =0; + virtual void write_to_stream(std::ostream&fd) const =0; // The emit virtual method is called by architecture emit to // output the generated code for the expression. The derived // class fills in the details of what exactly happened. - virtual int emit(ostream&out, Entity*ent, Architecture*arc) =0; + virtual int emit(ostream&out, Entity*ent, ScopeBase*scope) =0; // The emit_package virtual message is similar, but is called // in a package context and to emit SV packages. @@ -102,7 +103,7 @@ class Expression : public LineInfo { // argument if the evaluation works, or return false if it // cannot be done. virtual bool evaluate(ScopeBase*scope, int64_t&val) const; - virtual bool evaluate(Entity*ent, Architecture*arc, int64_t&val) const; + virtual bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; // The symbolic compare returns true if the two expressions @@ -134,6 +135,13 @@ class Expression : public LineInfo { Expression& operator = (const Expression&); }; +/* + * Checks before cloning if the other expression actually exists (!=NULL). + */ +static inline Expression*safe_clone(const Expression*other) { + return (other ? other->clone() : NULL); +} + static inline void FILE_NAME(Expression*tgt, const LineInfo*src) { tgt->set_line(*src); @@ -150,13 +158,15 @@ class ExpUnary : public Expression { ExpUnary(Expression*op1); virtual ~ExpUnary() =0; - const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const; + inline const Expression*peek_operand() const { return operand1_; } + + const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const; protected: - inline void write_to_stream_operand1(std::ostream&fd) + inline void write_to_stream_operand1(std::ostream&fd) const { operand1_->write_to_stream(fd); } - int emit_operand1(ostream&out, Entity*ent, Architecture*arc); + int emit_operand1(ostream&out, Entity*ent, ScopeBase*scope); void dump_operand1(ostream&out, int indent = 0) const; private: @@ -173,23 +183,23 @@ class ExpBinary : public Expression { ExpBinary(Expression*op1, Expression*op2); virtual ~ExpBinary() =0; - const Expression* peek_operand1(void) const { return operand1_; } - const Expression* peek_operand2(void) const { return operand2_; } + inline const Expression* peek_operand1(void) const { return operand1_; } + inline const Expression* peek_operand2(void) const { return operand2_; } - const VType*probe_type(Entity*ent, Architecture*arc) const; + const VType*probe_type(Entity*ent, ScopeBase*scope) const; protected: - int elaborate_exprs(Entity*, Architecture*, const VType*); - int emit_operand1(ostream&out, Entity*ent, Architecture*arc); - int emit_operand2(ostream&out, Entity*ent, Architecture*arc); + int elaborate_exprs(Entity*, ScopeBase*, const VType*); + int emit_operand1(ostream&out, Entity*ent, ScopeBase*scope); + int emit_operand2(ostream&out, Entity*ent, ScopeBase*scope); bool eval_operand1(ScopeBase*scope, int64_t&val) const; bool eval_operand2(ScopeBase*scope, int64_t&val) const; - inline void write_to_stream_operand1(std::ostream&out) + inline void write_to_stream_operand1(std::ostream&out) const { operand1_->write_to_stream(out); } - inline void write_to_stream_operand2(std::ostream&out) + inline void write_to_stream_operand2(std::ostream&out) const { operand2_->write_to_stream(out); } void dump_operands(ostream&out, int indent = 0) const; @@ -219,6 +229,9 @@ class ExpAggregate : public Expression { explicit choice_t(perm_string name); // discreate_range choice explicit choice_t(prange_t*ran); + + choice_t(const choice_t&other); + ~choice_t(); // true if this represents an "others" choice @@ -235,11 +248,17 @@ class ExpAggregate : public Expression { std::auto_ptrexpr_; std::auto_ptr range_; private: // not implemented - choice_t(const choice_t&); choice_t& operator= (const choice_t&); }; struct choice_element { + choice_element() : choice(), expr() {} + + choice_element(const choice_element&other) { + choice = other.choice ? new choice_t(*other.choice) : NULL; + expr = safe_clone(other.expr); + } + choice_t*choice; Expression*expr; bool alias_flag; @@ -251,6 +270,7 @@ class ExpAggregate : public Expression { class element_t { public: explicit element_t(std::list*fields, Expression*val); + element_t(const element_t&other); ~element_t(); size_t count_choices() const { return fields_.size(); } @@ -265,7 +285,6 @@ class ExpAggregate : public Expression { std::vectorfields_; Expression*val_; private: // not implemented - element_t(const element_t&); element_t& operator = (const element_t&); }; @@ -273,19 +292,20 @@ class ExpAggregate : public Expression { ExpAggregate(std::list*el); ~ExpAggregate(); + Expression*clone() const; - const VType*probe_type(Entity*ent, Architecture*arc) const; - const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const; - int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); - void write_to_stream(std::ostream&fd); - int emit(ostream&out, Entity*ent, Architecture*arc); + const VType*probe_type(Entity*ent, ScopeBase*scope) const; + const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const; + int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); + void write_to_stream(std::ostream&fd) const; + int emit(ostream&out, Entity*ent, ScopeBase*scope); void dump(ostream&out, int indent = 0) const; private: - int elaborate_expr_array_(Entity*ent, Architecture*arc, const VTypeArray*ltype); - int elaborate_expr_record_(Entity*ent, Architecture*arc, const VTypeRecord*ltype); - int emit_array_(ostream&out, Entity*ent, Architecture*arc, const VTypeArray*ltype); - int emit_record_(ostream&out, Entity*ent, Architecture*arc, const VTypeRecord*ltype); + int elaborate_expr_array_(Entity*ent, ScopeBase*scope, const VTypeArray*ltype); + int elaborate_expr_record_(Entity*ent, ScopeBase*scope, const VTypeRecord*ltype); + int emit_array_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeArray*ltype); + int emit_record_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeRecord*ltype); private: // This is the elements as directly parsed. @@ -305,9 +325,13 @@ class ExpArithmetic : public ExpBinary { ExpArithmetic(ExpArithmetic::fun_t op, Expression*op1, Expression*op2); ~ExpArithmetic(); - int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); - void write_to_stream(std::ostream&fd); - int emit(ostream&out, Entity*ent, Architecture*arc); + Expression*clone() const { + return new ExpArithmetic(fun_, peek_operand1()->clone(), peek_operand2()->clone()); + } + + int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); + void write_to_stream(std::ostream&fd) const; + int emit(ostream&out, Entity*ent, ScopeBase*scope); virtual bool evaluate(ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; @@ -324,16 +348,18 @@ class ExpAttribute : public Expression { ExpAttribute(ExpName*base, perm_string name); ~ExpAttribute(); + Expression*clone() const; + 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); - void write_to_stream(std::ostream&fd); - int emit(ostream&out, Entity*ent, Architecture*arc); + const VType*probe_type(Entity*ent, ScopeBase*scope) const; + int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); + void write_to_stream(std::ostream&fd) const; + int emit(ostream&out, Entity*ent, ScopeBase*scope); // Some attributes can be evaluated at compile time bool evaluate(ScopeBase*scope, int64_t&val) const; - bool evaluate(Entity*ent, Architecture*arc, int64_t&val) const; + bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; private: @@ -345,12 +371,15 @@ class ExpBitstring : public Expression { public: explicit ExpBitstring(const char*); + ExpBitstring(const ExpBitstring&other) : Expression() { value_ = other.value_; } ~ExpBitstring(); - const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const; - int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); - void write_to_stream(std::ostream&fd); - int emit(ostream&out, Entity*ent, Architecture*arc); + Expression*clone() const { return new ExpBitstring(*this); } + + const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const; + int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); + void write_to_stream(std::ostream&fd) const; + int emit(ostream&out, Entity*ent, ScopeBase*scope); void dump(ostream&out, int indent = 0) const; private: @@ -362,19 +391,22 @@ class ExpCharacter : public Expression { public: ExpCharacter(char val); + ExpCharacter(const ExpCharacter&other) : Expression() { value_ = other.value_; } ~ExpCharacter(); - const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const; - int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); - void write_to_stream(std::ostream&fd); - int emit(ostream&out, Entity*ent, Architecture*arc); + Expression*clone() const { return new ExpCharacter(*this); } + + const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const; + int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); + void write_to_stream(std::ostream&fd) const; + int emit(ostream&out, Entity*ent, ScopeBase*scope); bool is_primary(void) const; void dump(ostream&out, int indent = 0) const; char value() const { return value_; } private: - int emit_primitive_bit_(ostream&out, Entity*ent, Architecture*arc, + int emit_primitive_bit_(ostream&out, Entity*ent, ScopeBase*scope, const VTypePrimitive*etype); private: @@ -387,17 +419,21 @@ class ExpConcat : public Expression { ExpConcat(Expression*op1, Expression*op2); ~ExpConcat(); - const VType*probe_type(Entity*ent, Architecture*arc) const; - const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const; - int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); - void write_to_stream(std::ostream&fd); - int emit(ostream&out, Entity*ent, Architecture*arc); + Expression*clone() const { + return new ExpConcat(operand1_->clone(), operand2_->clone()); + } + + const VType*probe_type(Entity*ent, ScopeBase*scope) const; + const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const; + int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); + void write_to_stream(std::ostream&fd) const; + int emit(ostream&out, Entity*ent, ScopeBase*scope); virtual bool evaluate(ScopeBase*scope, int64_t&val) const; bool is_primary(void) const; void dump(ostream&out, int indent = 0) const; private: - int elaborate_expr_array_(Entity*ent, Architecture*arc, const VTypeArray*ltype); + int elaborate_expr_array_(Entity*ent, ScopeBase*scope, const VTypeArray*ltype); private: Expression*operand1_; @@ -415,11 +451,12 @@ class ExpConditional : public Expression { class else_t : public LineInfo { public: else_t(Expression*cond, std::list*tru); + else_t(const else_t&other); ~else_t(); - int elaborate_expr(Entity*ent, Architecture*arc, const VType*lt); - int emit_when_else(ostream&out, Entity*ent, Architecture*arc); - int emit_else(ostream&out, Entity*ent, Architecture*arc); + int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*lt); + int emit_when_else(ostream&out, Entity*ent, ScopeBase*scope); + int emit_else(ostream&out, Entity*ent, ScopeBase*scope); void dump(ostream&out, int indent = 0) const; private: @@ -432,10 +469,12 @@ class ExpConditional : public Expression { std::list*fal); ~ExpConditional(); - const VType*probe_type(Entity*ent, Architecture*arc) const; - int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); - void write_to_stream(std::ostream&fd); - int emit(ostream&out, Entity*ent, Architecture*arc); + Expression*clone() const; + + const VType*probe_type(Entity*ent, ScopeBase*scope) const; + int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); + void write_to_stream(std::ostream&fd) const; + int emit(ostream&out, Entity*ent, ScopeBase*scope); void dump(ostream&out, int indent = 0) const; private: @@ -457,10 +496,12 @@ class ExpEdge : public ExpUnary { explicit ExpEdge(ExpEdge::fun_t ty, Expression*op); ~ExpEdge(); + Expression*clone() const { return new ExpEdge(fun_, peek_operand()->clone()); } + inline fun_t edge_fun() const { return fun_; } - void write_to_stream(std::ostream&fd); - int emit(ostream&out, Entity*ent, Architecture*arc); + void write_to_stream(std::ostream&fd) const; + int emit(ostream&out, Entity*ent, ScopeBase*scope); void dump(ostream&out, int indent = 0) const; private: @@ -474,14 +515,17 @@ class ExpFunc : public Expression { ExpFunc(perm_string nn, std::list*args); ~ExpFunc(); + Expression*clone() const; + inline perm_string func_name() const { return name_; } inline size_t func_args() const { return argv_.size(); } inline const Expression*func_arg(size_t idx) const { return argv_[idx]; } + const VType*func_ret_type() const; public: // Base methods - int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); - void write_to_stream(std::ostream&fd); - int emit(ostream&out, Entity*ent, Architecture*arc); + int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); + void write_to_stream(std::ostream&fd) const; + int emit(ostream&out, Entity*ent, ScopeBase*scope); void dump(ostream&out, int indent = 0) const; private: @@ -494,14 +538,17 @@ class ExpInteger : public Expression { public: ExpInteger(int64_t val); + ExpInteger(const ExpInteger&other) : Expression(), value_(other.value_) {} ~ExpInteger(); - const VType*probe_type(Entity*ent, Architecture*arc) const; - int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); - void write_to_stream(std::ostream&fd); - int emit(ostream&out, Entity*ent, Architecture*arc); + Expression*clone() const { return new ExpInteger(*this); } + + const VType*probe_type(Entity*ent, ScopeBase*scope) const; + int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); + void write_to_stream(std::ostream&fd) const; + int emit(ostream&out, Entity*ent, ScopeBase*scope); int emit_package(std::ostream&out); - bool is_primary(void) const; + bool is_primary(void) const { return true; } bool evaluate(ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; virtual ostream& dump_inline(ostream&out) const; @@ -514,12 +561,15 @@ class ExpReal : public Expression { public: ExpReal(double val); + ExpReal(const ExpReal&other) : Expression(), value_(other.value_) {} ~ExpReal(); - const VType*probe_type(Entity*ent, Architecture*arc) const; - int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); - void write_to_stream(std::ostream&fd); - int emit(ostream&out, Entity*ent, Architecture*arc); + Expression*clone() const { return new ExpReal(*this); } + + const VType*probe_type(Entity*ent, ScopeBase*scope) const; + int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); + void write_to_stream(std::ostream&fd) const; + int emit(ostream&out, Entity*ent, ScopeBase*scope); int emit_package(std::ostream&out); bool is_primary(void) const; void dump(ostream&out, int indent = 0) const; @@ -538,11 +588,15 @@ class ExpLogical : public ExpBinary { ExpLogical(ExpLogical::fun_t ty, Expression*op1, Expression*op2); ~ExpLogical(); + Expression*clone() const { + return new ExpLogical(fun_, peek_operand1()->clone(), peek_operand2()->clone()); + } + inline fun_t logic_fun() const { return fun_; } - int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); - void write_to_stream(std::ostream&fd); - int emit(ostream&out, Entity*ent, Architecture*arc); + int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); + void write_to_stream(std::ostream&fd) const; + int emit(ostream&out, Entity*ent, ScopeBase*scope); void dump(ostream&out, int indent = 0) const; private: @@ -565,31 +619,35 @@ class ExpName : public Expression { ~ExpName(); public: // Base methods - int elaborate_lval(Entity*ent, Architecture*arc, bool); - int elaborate_rval(Entity*ent, Architecture*arc, const InterfacePort*); - const VType* probe_type(Entity*ent, Architecture*arc) const; - const VType* fit_type(Entity*ent, Architecture*arc, const VTypeArray*host) const; - int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); - void write_to_stream(std::ostream&fd); - int emit(ostream&out, Entity*ent, Architecture*arc); + Expression*clone() const { + return new ExpName(static_cast(safe_clone(prefix_.get())), + name_, safe_clone(index_), safe_clone(lsb_)); + } + int elaborate_lval(Entity*ent, ScopeBase*scope, bool); + int elaborate_rval(Entity*ent, ScopeBase*scope, const InterfacePort*); + const VType* probe_type(Entity*ent, ScopeBase*scope) const; + const VType* fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*host) const; + int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); + void write_to_stream(std::ostream&fd) const; + int emit(ostream&out, Entity*ent, ScopeBase*scope); bool is_primary(void) const; bool evaluate(ScopeBase*scope, int64_t&val) const; - bool evaluate(Entity*ent, Architecture*arc, int64_t&val) const; + 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 perm_string peek_name() const { return name_; } + inline const perm_string& peek_name() const { return name_; } void set_range(Expression*msb, Expression*lsb); private: - const VType* elaborate_adjust_type_with_range_(Entity*ent, Architecture*arc, const VType*type); + const VType* elaborate_adjust_type_with_range_(Entity*ent, ScopeBase*scope, const VType*type); - int elaborate_lval_(Entity*ent, Architecture*arc, bool, ExpName*suffix); - const VType* probe_prefix_type_(Entity*ent, Architecture*arc) const; - const VType* probe_prefixed_type_(Entity*ent, Architecture*arc) const; + int elaborate_lval_(Entity*ent, ScopeBase*scope, bool, ExpName*suffix); + const VType* probe_prefix_type_(Entity*ent, ScopeBase*scope) const; + const VType* probe_prefixed_type_(Entity*ent, ScopeBase*scope) const; - int emit_as_prefix_(ostream&out, Entity*ent, Architecture*arc); + int emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope); private: std::auto_ptr prefix_; @@ -604,8 +662,8 @@ class ExpNameALL : public ExpName { ExpNameALL() : ExpName(perm_string()) { } public: - int elaborate_lval(Entity*ent, Architecture*arc, bool); - const VType* probe_type(Entity*ent, Architecture*arc) const; + int elaborate_lval(Entity*ent, ScopeBase*scope, bool); + const VType* probe_type(Entity*ent, ScopeBase*scope) const; void dump(ostream&out, int indent =0) const; }; @@ -620,10 +678,14 @@ class ExpRelation : public ExpBinary { ExpRelation(ExpRelation::fun_t ty, Expression*op1, Expression*op2); ~ExpRelation(); - const VType* probe_type(Entity*ent, Architecture*arc) const; - int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); - void write_to_stream(std::ostream&fd); - int emit(ostream&out, Entity*ent, Architecture*arc); + Expression*clone() const { + return new ExpRelation(fun_, peek_operand1()->clone(), peek_operand2()->clone()); + } + + const VType* probe_type(Entity*ent, ScopeBase*scope) const; + int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); + void write_to_stream(std::ostream&fd) const; + int emit(ostream&out, Entity*ent, ScopeBase*scope); void dump(ostream&out, int indent = 0) const; private: @@ -634,18 +696,21 @@ class ExpString : public Expression { public: explicit ExpString(const char*); + ExpString(const ExpString&other) : Expression(), value_(other.value_) {} ~ExpString(); - const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const; - int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); - void write_to_stream(std::ostream&fd); - int emit(ostream&out, Entity*ent, Architecture*arc); + Expression*clone() const { return new ExpString(*this); } + + const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const; + int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); + void write_to_stream(std::ostream&fd) const; + int emit(ostream&out, Entity*ent, ScopeBase*scope); bool is_primary(void) const; void dump(ostream&out, int indent = 0) const; const std::vector& get_value() const { return value_; } private: - int emit_as_array_(ostream&out, Entity*ent, Architecture*arc, const VTypeArray*arr); + int emit_as_array_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeArray*arr); private: std::vector value_; @@ -657,8 +722,10 @@ class ExpUAbs : public ExpUnary { ExpUAbs(Expression*op1); ~ExpUAbs(); - void write_to_stream(std::ostream&fd); - int emit(ostream&out, Entity*ent, Architecture*arc); + Expression*clone() const { return new ExpUAbs(peek_operand()->clone()); } + + void write_to_stream(std::ostream&fd) const; + int emit(ostream&out, Entity*ent, ScopeBase*scope); void dump(ostream&out, int indent = 0) const; }; @@ -668,10 +735,56 @@ class ExpUNot : public ExpUnary { ExpUNot(Expression*op1); ~ExpUNot(); - int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); - void write_to_stream(std::ostream&fd); - int emit(ostream&out, Entity*ent, Architecture*arc); + Expression*clone() const { return new ExpUNot(peek_operand()->clone()); } + + int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); + void write_to_stream(std::ostream&fd) const; + int emit(ostream&out, Entity*ent, ScopeBase*scope); void dump(ostream&out, int indent = 0) const; }; +/* + * Class that wraps other expressions to cast them to other types. + */ +class ExpCast : public Expression { + + public: + ExpCast(Expression*base, const VType*type); + ~ExpCast(); + + Expression*clone() const { return new ExpCast(base_->clone(), type_->clone()); } + + inline int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) { + return base_->elaborate_expr(ent, scope, type_); + } + void write_to_stream(std::ostream&fd) const; + int emit(ostream&out, Entity*ent, ScopeBase*scope); + void dump(ostream&out, int indent = 0) const; + + private: + Expression*base_; + const VType*type_; +}; + +/* + * Class that handles 'new' statement. VHDL is not capable of dynamic memory + * allocation, but it is useful for emitting some cases. + */ +class ExpNew : public Expression { + + public: + ExpNew(Expression*size); + ~ExpNew(); + + Expression*clone() const { return new ExpNew(size_->clone()); } + + // There is no 'new' in VHDL - do not emit anything + void write_to_stream(std::ostream&) const {}; + int emit(ostream&out, Entity*ent, ScopeBase*scope); + void dump(ostream&out, int indent = 0) const; + + private: + Expression*size_; +}; + #endif /* IVL_expression_H */ diff --git a/vhdlpp/expression_debug.cc b/vhdlpp/expression_debug.cc index befd6ea84..deeb3099e 100644 --- a/vhdlpp/expression_debug.cc +++ b/vhdlpp/expression_debug.cc @@ -68,3 +68,17 @@ void ExpConcat::dump(ostream&out, int indent) const operand1_->dump(out, indent); operand2_->dump(out, indent); } + +void ExpCast::dump(ostream&out, int indent) const +{ + out << "Casting "; + base_->dump(out, indent+4); + out << " to "; + type_->emit_def(out, empty_perm_string); +} + +void ExpNew::dump(ostream&out, int indent) const +{ + out << "New dynamic array size: "; + size_->dump(out, indent); +} diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index b07ff6994..d16f63db4 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -33,20 +33,20 @@ using namespace std; -int Expression::elaborate_lval(Entity*, Architecture*, bool) +int Expression::elaborate_lval(Entity*, ScopeBase*, bool) { cerr << get_fileline() << ": error: Expression is not a valid l-value." << endl; return 1; } -const VType* Expression::probe_type(Entity*, Architecture*) const +const VType* Expression::probe_type(Entity*, ScopeBase*) const { return 0; } -const VType* Expression::fit_type(Entity*ent, Architecture*arc, const VTypeArray*) const +const VType* Expression::fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*) const { - const VType*res = probe_type(ent,arc); + const VType*res = probe_type(ent,scope); if (res == 0) { cerr << get_fileline() << ": internal error: " << "fit_type for " << typeid(*this).name() @@ -56,7 +56,7 @@ const VType* Expression::fit_type(Entity*ent, Architecture*arc, const VTypeArray return res; } -const VType*ExpName::elaborate_adjust_type_with_range_(Entity*, Architecture*arc, const VType*type) +const VType*ExpName::elaborate_adjust_type_with_range_(Entity*, ScopeBase*scope, const VType*type) { // Unfold typedefs while (const VTypeDef*tdef = dynamic_cast(type)) { @@ -75,9 +75,9 @@ const VType*ExpName::elaborate_adjust_type_with_range_(Entity*, Architecture*arc int64_t use_msb, use_lsb; bool flag; - flag = index_->evaluate(arc, use_msb); + flag = index_->evaluate(scope, use_msb); ivl_assert(*this, flag); - flag = lsb_->evaluate(arc, use_lsb); + flag = lsb_->evaluate(scope, use_lsb); ivl_assert(*this, flag); Expression*exp_msb = new ExpInteger(use_msb); @@ -91,7 +91,7 @@ const VType*ExpName::elaborate_adjust_type_with_range_(Entity*, Architecture*arc return type; } -int ExpName::elaborate_lval_(Entity*ent, Architecture*arc, bool is_sequ, ExpName*suffix) +int ExpName::elaborate_lval_(Entity*ent, ScopeBase*scope, bool is_sequ, ExpName*suffix) { int errors = 0; @@ -134,13 +134,13 @@ int ExpName::elaborate_lval_(Entity*ent, Architecture*arc, bool is_sequ, ExpName << ent->get_name() << "." << endl; return errors + 1; - } else if (Signal*sig = arc->find_signal(name_)) { + } else if (Signal*sig = scope->find_signal(name_)) { // Tell the target signal that this may be a sequential l-value. if (is_sequ) sig->count_ref_sequ(); found_type = sig->peek_type(); - } else if (Variable*var = arc->find_variable(name_)) { + } else if (Variable*var = scope->find_variable(name_)) { // Tell the target signal that this may be a sequential l-value. if (is_sequ) var->count_ref_sequ(); @@ -201,7 +201,7 @@ int ExpName::elaborate_lval_(Entity*ent, Architecture*arc, bool is_sequ, ExpName return errors; } - suffix_type = suffix->elaborate_adjust_type_with_range_(ent, arc, suffix_type); + suffix_type = suffix->elaborate_adjust_type_with_range_(ent, scope, suffix_type); ivl_assert(*this, suffix_type); suffix->set_type(suffix_type); @@ -209,12 +209,12 @@ int ExpName::elaborate_lval_(Entity*ent, Architecture*arc, bool is_sequ, ExpName return errors; } -int ExpName::elaborate_lval(Entity*ent, Architecture*arc, bool is_sequ) +int ExpName::elaborate_lval(Entity*ent, ScopeBase*scope, bool is_sequ) { int errors = 0; if (prefix_.get()) { - return prefix_->elaborate_lval_(ent, arc, is_sequ, this); + return prefix_->elaborate_lval_(ent, scope, is_sequ, this); } const VType*found_type = 0; @@ -238,13 +238,13 @@ int ExpName::elaborate_lval(Entity*ent, Architecture*arc, bool is_sequ) << ent->get_name() << "." << endl; return 1; - } else if (Signal*sig = arc->find_signal(name_)) { + } else if (Signal*sig = scope->find_signal(name_)) { // Tell the target signal that this may be a sequential l-value. if (is_sequ) sig->count_ref_sequ(); found_type = sig->peek_type(); - } else if (Variable*var = arc->find_variable(name_)) { + } else if (Variable*var = scope->find_variable(name_)) { // Tell the target signal that this may be a sequential l-value. if (is_sequ) var->count_ref_sequ(); @@ -257,13 +257,13 @@ int ExpName::elaborate_lval(Entity*ent, Architecture*arc, bool is_sequ) return errors + 1; } - found_type = elaborate_adjust_type_with_range_(ent, arc, found_type); + found_type = elaborate_adjust_type_with_range_(ent, scope, found_type); set_type(found_type); return errors; } -int ExpName::elaborate_rval(Entity*ent, Architecture*arc, const InterfacePort*lval) +int ExpName::elaborate_rval(Entity*ent, ScopeBase*scope, const InterfacePort*lval) { int errors = 0; @@ -295,7 +295,7 @@ int ExpName::elaborate_rval(Entity*ent, Architecture*arc, const InterfacePort*lv default: break; } - } else if (arc->find_signal(name_)) { + } else if (scope->find_signal(name_)) { /* OK */ } else if (ent->find_generic(name_)) { @@ -310,21 +310,21 @@ int ExpName::elaborate_rval(Entity*ent, Architecture*arc, const InterfacePort*lv return errors; } -int ExpNameALL::elaborate_lval(Entity*ent, Architecture*arc, bool is_sequ) +int ExpNameALL::elaborate_lval(Entity*ent, ScopeBase*scope, bool is_sequ) { - return Expression::elaborate_lval(ent, arc, is_sequ); + return Expression::elaborate_lval(ent, scope, is_sequ); } -int Expression::elaborate_expr(Entity*, Architecture*, const VType*) +int Expression::elaborate_expr(Entity*, ScopeBase*, const VType*) { cerr << get_fileline() << ": internal error: I don't know how to elaborate expression type=" << typeid(*this).name() << endl; return 1; } -const VType* ExpBinary::probe_type(Entity*ent, Architecture*arc) const +const VType* ExpBinary::probe_type(Entity*ent, ScopeBase*scope) const { - const VType*t1 = operand1_->probe_type(ent, arc); - const VType*t2 = operand2_->probe_type(ent, arc); + const VType*t1 = operand1_->probe_type(ent, scope); + const VType*t2 = operand2_->probe_type(ent, scope); if (t1 == 0) return t2; @@ -351,12 +351,12 @@ const VType*ExpBinary::resolve_operand_types_(const VType*, const VType*) const return 0; } -int ExpBinary::elaborate_exprs(Entity*ent, Architecture*arc, const VType*ltype) +int ExpBinary::elaborate_exprs(Entity*ent, ScopeBase*scope, const VType*ltype) { int errors = 0; - errors += operand1_->elaborate_expr(ent, arc, ltype); - errors += operand2_->elaborate_expr(ent, arc, ltype); + errors += operand1_->elaborate_expr(ent, scope, ltype); + errors += operand2_->elaborate_expr(ent, scope, ltype); return errors; } @@ -365,17 +365,17 @@ int ExpBinary::elaborate_exprs(Entity*ent, Architecture*arc, const VType*ltype) * return the fit_type for the operand. The assumption is that the * operator doesn't change the type. */ -const VType*ExpUnary::fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const +const VType*ExpUnary::fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const { - return operand1_->fit_type(ent, arc, atype); + return operand1_->fit_type(ent, scope, atype); } -const VType*ExpAggregate::probe_type(Entity*ent, Architecture*arc) const +const VType*ExpAggregate::probe_type(Entity*ent, ScopeBase*scope) const { - return Expression::probe_type(ent, arc); + return Expression::probe_type(ent, scope); } -const VType*ExpAggregate::fit_type(Entity*, Architecture*, const VTypeArray*host) const +const VType*ExpAggregate::fit_type(Entity*, ScopeBase*, const VTypeArray*host) const { ivl_assert(*this, elements_.size() == 1); size_t choice_count = elements_[0]->count_choices(); @@ -401,7 +401,7 @@ const VType*ExpAggregate::fit_type(Entity*, Architecture*, const VTypeArray*host return res; } -int ExpAggregate::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) +int ExpAggregate::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) { if (ltype == 0) { cerr << get_fileline() << ": error: Elaboration of aggregate types needs well known type context?" << endl; @@ -415,10 +415,10 @@ int ExpAggregate::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype } if (const VTypeArray*larray = dynamic_cast(ltype)) { - return elaborate_expr_array_(ent, arc, larray); + return elaborate_expr_array_(ent, scope, larray); } else if(const VTypeRecord*lrecord = dynamic_cast(ltype)) { - return elaborate_expr_record_(ent, arc, lrecord); + return elaborate_expr_record_(ent, scope, lrecord); } cerr << get_fileline() << ": internal error: I don't know how to elaborate aggregate expressions. type=" << typeid(*ltype).name() << endl; @@ -430,7 +430,7 @@ int ExpAggregate::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype * expressions (the elements_ member) using the element type as the * ltype for the subexpression. */ -int ExpAggregate::elaborate_expr_array_(Entity*ent, Architecture*arc, const VTypeArray*ltype) +int ExpAggregate::elaborate_expr_array_(Entity*ent, ScopeBase*scope, const VTypeArray*ltype) { const VType*element_type = ltype->element_type(); int errors = 0; @@ -476,7 +476,7 @@ int ExpAggregate::elaborate_expr_array_(Entity*ent, Architecture*arc, const VTyp if (aggregate_[idx].alias_flag) continue; - errors += aggregate_[idx].expr->elaborate_expr(ent, arc, element_type); + errors += aggregate_[idx].expr->elaborate_expr(ent, scope, element_type); } // done with the obsolete elements_ vector. @@ -485,7 +485,7 @@ int ExpAggregate::elaborate_expr_array_(Entity*ent, Architecture*arc, const VTyp return errors; } -int ExpAggregate::elaborate_expr_record_(Entity*ent, Architecture*arc, const VTypeRecord*ltype) +int ExpAggregate::elaborate_expr_record_(Entity*ent, ScopeBase*scope, const VTypeRecord*ltype) { int errors = 0; @@ -513,10 +513,12 @@ int ExpAggregate::elaborate_expr_record_(Entity*ent, Architecture*arc, const VTy ivl_assert(*this, field); perm_string field_name = field->peek_name(); + idx = -1; const VTypeRecord::element_t*el = ltype->element_by_name(field_name, &idx); + ivl_assert(*this, idx >= 0); aggregate_[idx] = tmp; - errors += aggregate_[idx].expr->elaborate_expr(ent, arc, el->peek_type()); + errors += aggregate_[idx].expr->elaborate_expr(ent, scope, el->peek_type()); } // done with the obsolete elements_ vector. @@ -535,16 +537,16 @@ void ExpAggregate::element_t::map_choices(ExpAggregate::choice_element*dst) } } -int ExpArithmetic::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) +int ExpArithmetic::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) { int errors = 0; if (ltype == 0) { - ltype = probe_type(ent, arc); + ltype = probe_type(ent, scope); } ivl_assert(*this, ltype != 0); - errors += elaborate_exprs(ent, arc, ltype); + errors += elaborate_exprs(ent, scope, ltype); return errors; } @@ -563,9 +565,9 @@ const VType* ExpArithmetic::resolve_operand_types_(const VType*t1, const VType*t return 0; } -const VType* ExpAttribute::probe_type(Entity*ent, Architecture*arc) const +const VType* ExpAttribute::probe_type(Entity*ent, ScopeBase*scope) const { - base_->probe_type(ent, arc); + base_->probe_type(ent, scope); if (name_ == "length" || name_ == "left" || name_ == "right") { return &primitive_INTEGER; @@ -574,42 +576,46 @@ const VType* ExpAttribute::probe_type(Entity*ent, Architecture*arc) const return 0; } -int ExpAttribute::elaborate_expr(Entity*ent, Architecture*arc, const VType*) +int ExpAttribute::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) { int errors = 0; - const VType*sub_type = base_->probe_type(ent, arc); - errors += base_->elaborate_expr(ent, arc, sub_type); + const VType*sub_type = base_->probe_type(ent, scope); + errors += base_->elaborate_expr(ent, scope, sub_type); return errors; } -const VType*ExpBitstring::fit_type(Entity*, Architecture*, const VTypeArray*atype) const +const VType*ExpBitstring::fit_type(Entity*, ScopeBase*, const VTypeArray*atype) const { // Really should check that this string can work with the // array element type? return atype->element_type(); } -int ExpBitstring::elaborate_expr(Entity*, Architecture*, const VType*) +int ExpBitstring::elaborate_expr(Entity*, ScopeBase*, const VType*) { int errors = 0; + std::vector range; + range.push_back(VTypeArray::range_t(new ExpInteger(value_.size() - 1), new ExpInteger(0))); + const VTypeArray*type = new VTypeArray(&primitive_STDLOGIC, range); + set_type(type); return errors; } -const VType*ExpCharacter::fit_type(Entity*, Architecture*, const VTypeArray*atype) const +const VType*ExpCharacter::fit_type(Entity*, ScopeBase*, const VTypeArray*atype) const { // Really should check that this character can work with the // array element type? return atype->element_type(); } -int ExpCharacter::elaborate_expr(Entity*, Architecture*, const VType*ltype) +int ExpCharacter::elaborate_expr(Entity*, ScopeBase*, const VType*ltype) { ivl_assert(*this, ltype != 0); set_type(ltype); return 0; } -const VType*ExpConcat::fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const +const VType*ExpConcat::fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const { Expression*operands[2] = {operand1_, operand2_}; const VType*types[2] = {NULL, NULL}; @@ -617,7 +623,7 @@ const VType*ExpConcat::fit_type(Entity*ent, Architecture*arc, const VTypeArray*a // determine the type and size of concatenated expressions for(int i = 0; i < 2; ++i) { - types[i] = operands[i]->fit_type(ent, arc, atype); + types[i] = operands[i]->fit_type(ent, scope, atype); if(const VTypeArray*arr = dynamic_cast(types[i])) { types[i] = arr->element_type(); @@ -645,62 +651,62 @@ const VType*ExpConcat::fit_type(Entity*ent, Architecture*arc, const VTypeArray*a /* * I don't know how to probe the type of a concatenation, quite yet. */ -const VType*ExpConcat::probe_type(Entity*, Architecture*) const +const VType*ExpConcat::probe_type(Entity*, ScopeBase*) const { ivl_assert(*this, 0); return 0; } -int ExpConcat::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) +int ExpConcat::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) { int errors = 0; if (ltype == 0) { - ltype = probe_type(ent, arc); + ltype = probe_type(ent, scope); } ivl_assert(*this, ltype != 0); if (const VTypeArray*atype = dynamic_cast(ltype)) { - errors += elaborate_expr_array_(ent, arc, atype); + errors += elaborate_expr_array_(ent, scope, atype); } else { - errors += operand1_->elaborate_expr(ent, arc, ltype); - errors += operand2_->elaborate_expr(ent, arc, ltype); + errors += operand1_->elaborate_expr(ent, scope, ltype); + errors += operand2_->elaborate_expr(ent, scope, ltype); } return errors; } -int ExpConcat::elaborate_expr_array_(Entity*ent, Architecture*arc, const VTypeArray*atype) +int ExpConcat::elaborate_expr_array_(Entity*ent, ScopeBase*scope, const VTypeArray*atype) { int errors = 0; // For now, only support single-dimension arrays here. ivl_assert(*this, atype->dimensions() == 1); - const VType*type1 = operand1_->fit_type(ent, arc, atype); + const VType*type1 = operand1_->fit_type(ent, scope, atype); ivl_assert(*this, type1); - const VType*type2 = operand2_->fit_type(ent, arc, atype); + const VType*type2 = operand2_->fit_type(ent, scope, atype); ivl_assert(*this, type2); - errors += operand1_->elaborate_expr(ent, arc, type1); - errors += operand2_->elaborate_expr(ent, arc, type2); + errors += operand1_->elaborate_expr(ent, scope, type1); + errors += operand2_->elaborate_expr(ent, scope, type2); return errors; } -const VType* ExpConditional::probe_type(Entity*, Architecture*) const +const VType* ExpConditional::probe_type(Entity*, ScopeBase*) const { return 0; } -int ExpConditional::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) +int ExpConditional::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) { int errors = 0; if (ltype == 0) - ltype = probe_type(ent, arc); + ltype = probe_type(ent, scope); ivl_assert(*this, ltype); @@ -708,42 +714,42 @@ int ExpConditional::elaborate_expr(Entity*ent, Architecture*arc, const VType*lty /* Note that the type for the condition expression need not have anything to do with the type of this expression. */ - errors += cond_->elaborate_expr(ent, arc, 0); + errors += cond_->elaborate_expr(ent, scope, 0); for (list::const_iterator cur = true_clause_.begin() ; cur != true_clause_.end() ; ++cur) { - errors += (*cur)->elaborate_expr(ent, arc, ltype); + errors += (*cur)->elaborate_expr(ent, scope, ltype); } for (list::const_iterator cur = else_clause_.begin() ; cur != else_clause_.end() ; ++cur) { - errors += (*cur)->elaborate_expr(ent, arc, ltype); + errors += (*cur)->elaborate_expr(ent, scope, ltype); } return errors; } -int ExpConditional::else_t::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) +int ExpConditional::else_t::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) { int errors = 0; if (cond_) - errors += cond_->elaborate_expr(ent, arc, 0); + errors += cond_->elaborate_expr(ent, scope, 0); for (list::const_iterator cur = true_clause_.begin() ; cur != true_clause_.end() ; ++cur) { - errors += (*cur)->elaborate_expr(ent, arc, ltype); + errors += (*cur)->elaborate_expr(ent, scope, ltype); } return errors; } -int ExpFunc::elaborate_expr(Entity*ent, Architecture*arc, const VType*) +int ExpFunc::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) { int errors = 0; - ivl_assert(*this, arc); - Subprogram*prog = arc->find_subprogram(name_); + ivl_assert(*this, scope); + Subprogram*prog = scope->find_subprogram(name_); if(!prog) prog = library_find_subprogram(name_); @@ -751,27 +757,36 @@ int ExpFunc::elaborate_expr(Entity*ent, Architecture*arc, const VType*) ivl_assert(*this, def_==0); def_ = prog; + // Elaborate arguments for (size_t idx = 0 ; idx < argv_.size() ; idx += 1) { - const VType*tmp = argv_[idx]->probe_type(ent, arc); - if(!tmp && prog) - tmp = prog->peek_param_type(idx); - errors += argv_[idx]->elaborate_expr(ent, arc, tmp); + const VType*tmp = argv_[idx]->probe_type(ent, scope); + const VType*param_type = prog ? prog->peek_param_type(idx) : NULL; + + if(!tmp && param_type) + tmp = param_type; + + errors += argv_[idx]->elaborate_expr(ent, scope, tmp); + } + + if(def_ && def_->unbounded()) { + def_ = prog->make_instance(argv_, scope); + name_ = def_->name(); } return errors; } -const VType* ExpInteger::probe_type(Entity*, Architecture*) const +const VType* ExpInteger::probe_type(Entity*, ScopeBase*) const { return &primitive_INTEGER; } -int ExpInteger::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) +int ExpInteger::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) { int errors = 0; if (ltype == 0) { - ltype = probe_type(ent, arc); + ltype = probe_type(ent, scope); } ivl_assert(*this, ltype != 0); @@ -779,17 +794,17 @@ int ExpInteger::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) return errors; } -const VType* ExpReal::probe_type(Entity*, Architecture*) const +const VType* ExpReal::probe_type(Entity*, ScopeBase*) const { return &primitive_REAL; } -int ExpReal::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) +int ExpReal::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) { int errors = 0; if (ltype == 0) { - ltype = probe_type(ent, arc); + ltype = probe_type(ent, scope); } ivl_assert(*this, ltype != 0); @@ -797,27 +812,27 @@ int ExpReal::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) return errors; } -int ExpLogical::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) +int ExpLogical::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) { int errors = 0; if (ltype == 0) { - ltype = probe_type(ent, arc); + ltype = probe_type(ent, scope); } ivl_assert(*this, ltype != 0); - errors += elaborate_exprs(ent, arc, ltype); + errors += elaborate_exprs(ent, scope, ltype); return errors; } -const VType* ExpName::probe_prefix_type_(Entity*ent, Architecture*arc) const +const VType* ExpName::probe_prefix_type_(Entity*ent, ScopeBase*scope) const { if (prefix_.get()) { cerr << get_fileline() << ": sorry: I do not know how to support nested prefix parts." << endl; return 0; } - const VType*type = probe_type(ent, arc); + const VType*type = probe_type(ent, scope); return type; } @@ -826,10 +841,10 @@ const VType* ExpName::probe_prefix_type_(Entity*ent, Architecture*arc) const * that have prefix parts. In this case we try to get the type of the * prefix and interpret the name in that context. */ -const VType* ExpName::probe_prefixed_type_(Entity*ent, Architecture*arc) const +const VType* ExpName::probe_prefixed_type_(Entity*ent, ScopeBase*scope) const { // First, get the type of the prefix. - const VType*prefix_type = prefix_->probe_prefix_type_(ent, arc); + const VType*prefix_type = prefix_->probe_prefix_type_(ent, scope); if (prefix_type == 0) { return 0; } @@ -857,34 +872,40 @@ const VType* ExpName::probe_prefixed_type_(Entity*ent, Architecture*arc) const return 0; } -const VType* ExpName::probe_type(Entity*ent, Architecture*arc) const +const VType* ExpName::probe_type(Entity*ent, ScopeBase*scope) const { if (prefix_.get()) - return probe_prefixed_type_(ent, arc); + return probe_prefixed_type_(ent, scope); - if (const InterfacePort*cur = ent->find_port(name_)) { - ivl_assert(*this, cur->type); - return cur->type; + if(ent) { + if (const InterfacePort*cur = ent->find_port(name_)) { + ivl_assert(*this, cur->type); + return cur->type; + } + + if (const InterfacePort*cur = ent->find_generic(name_)) { + ivl_assert(*this, cur->type); + return cur->type; + } } - if (const InterfacePort*cur = ent->find_generic(name_)) { - ivl_assert(*this, cur->type); - return cur->type; - } + if(scope) { + if (Signal*sig = scope->find_signal(name_)) + return sig->peek_type(); - if (Signal*sig = arc->find_signal(name_)) - return sig->peek_type(); + if (Variable*var = scope->find_variable(name_)) + return var->peek_type(); - if (Variable*var = arc->find_variable(name_)) - return var->peek_type(); + const VType*ctype = 0; + Expression*cval = 0; + if (scope->find_constant(name_, ctype, cval)) + return ctype; - const VType*ctype = 0; - Expression*cval = 0; - if (arc->find_constant(name_, ctype, cval)) - return ctype; - - if (const VType*gtype = arc->probe_genvar_type(name_)) { - return gtype; + const VType*gtype = 0; + Architecture*arc = dynamic_cast(scope); + if (arc && (gtype = arc->probe_genvar_type(name_))) { + return gtype; + } } cerr << get_fileline() << ": error: Signal/variable " << name_ @@ -892,12 +913,12 @@ const VType* ExpName::probe_type(Entity*ent, Architecture*arc) const return 0; } -const VType* ExpName::fit_type(Entity*ent, Architecture*arc, const VTypeArray*)const +const VType* ExpName::fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*)const { - return probe_type(ent, arc); + return probe_type(ent, scope); } -int ExpName::elaborate_expr(Entity*, Architecture*, const VType*ltype) +int ExpName::elaborate_expr(Entity*, ScopeBase*, const VType*ltype) { if (ltype) { ivl_assert(*this, ltype != 0); @@ -907,22 +928,22 @@ int ExpName::elaborate_expr(Entity*, Architecture*, const VType*ltype) return 0; } -const VType* ExpNameALL::probe_type(Entity*, Architecture*) const +const VType* ExpNameALL::probe_type(Entity*, ScopeBase*) const { return 0; } -const VType* ExpRelation::probe_type(Entity*, Architecture*) const +const VType* ExpRelation::probe_type(Entity*, ScopeBase*) const { return &primitive_BOOLEAN; } -int ExpRelation::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) +int ExpRelation::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) { int errors = 0; if (ltype == 0) { - ltype = probe_type(ent, arc); + ltype = probe_type(ent, scope); } ivl_assert(*this, ltype != 0); @@ -930,8 +951,8 @@ int ExpRelation::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) // The type of the operands must match, but need not match the // type for the ExpRelation itself. So get the operand type // separately. - const VType*otype = ExpBinary::probe_type(ent, arc); - errors += elaborate_exprs(ent, arc, otype); + const VType*otype = ExpBinary::probe_type(ent, scope); + errors += elaborate_exprs(ent, scope, otype); return errors; } @@ -941,7 +962,7 @@ int ExpRelation::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) * string is an array with the same element type of the concatenation, * but with elements for each character of the string. */ -const VType*ExpString::fit_type(Entity*, Architecture*, const VTypeArray*atype) const +const VType*ExpString::fit_type(Entity*, ScopeBase*, const VTypeArray*atype) const { vector range (atype->dimensions()); @@ -957,14 +978,14 @@ const VType*ExpString::fit_type(Entity*, Architecture*, const VTypeArray*atype) return type; } -int ExpString::elaborate_expr(Entity*, Architecture*, const VType*ltype) +int ExpString::elaborate_expr(Entity*, ScopeBase*, const VType*ltype) { ivl_assert(*this, ltype != 0); set_type(ltype); return 0; } -int ExpUNot::elaborate_expr(Entity*, Architecture*, const VType*ltype) +int ExpUNot::elaborate_expr(Entity*, ScopeBase*, const VType*ltype) { ivl_assert(*this, ltype != 0); set_type(ltype); diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 2c1e510e5..bf5d47e92 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -33,7 +33,7 @@ using namespace std; -int Expression::emit(ostream&out, Entity*, Architecture*) +int Expression::emit(ostream&out, Entity*, ScopeBase*) { out << " /* " << get_fileline() << ": internal error: " << "I don't know how to emit this expression! " @@ -54,34 +54,34 @@ bool Expression::is_primary(void) const return false; } -int ExpBinary::emit_operand1(ostream&out, Entity*ent, Architecture*arc) +int ExpBinary::emit_operand1(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; bool oper_primary = operand1_->is_primary(); if (! oper_primary) out << "("; - errors += operand1_->emit(out, ent, arc); + errors += operand1_->emit(out, ent, scope); if (! oper_primary) out << ")"; return errors; } -int ExpBinary::emit_operand2(ostream&out, Entity*ent, Architecture*arc) +int ExpBinary::emit_operand2(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; bool oper_primary = operand2_->is_primary(); if (! oper_primary) out << "("; - errors += operand2_->emit(out, ent, arc); + errors += operand2_->emit(out, ent, scope); if (! oper_primary) out << ")"; return errors; } -int ExpUnary::emit_operand1(ostream&out, Entity*ent, Architecture*arc) +int ExpUnary::emit_operand1(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; - errors += operand1_->emit(out, ent, arc); + errors += operand1_->emit(out, ent, scope); return errors; } -int ExpAggregate::emit(ostream&out, Entity*ent, Architecture*arc) +int ExpAggregate::emit(ostream&out, Entity*ent, ScopeBase*scope) { if (peek_type() == 0) { out << "/* " << get_fileline() << ": internal error: " @@ -95,9 +95,9 @@ int ExpAggregate::emit(ostream&out, Entity*ent, Architecture*arc) } if (const VTypeArray*atype = dynamic_cast (use_type)) - return emit_array_(out, ent, arc, atype); + return emit_array_(out, ent, scope, atype); else if (const VTypeRecord*arecord = dynamic_cast (use_type)) - return emit_record_(out, ent, arc, arecord); + return emit_record_(out, ent, scope, arecord); out << "/* " << get_fileline() << ": internal error: " << "I don't know how to elab/emit aggregate in " << typeid(use_type).name() @@ -105,7 +105,7 @@ int ExpAggregate::emit(ostream&out, Entity*ent, Architecture*arc) return 1; } -int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const VTypeArray*atype) +int ExpAggregate::emit_array_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeArray*atype) { int errors = 0; @@ -119,14 +119,14 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V int64_t use_msb; int64_t use_lsb; bool rc_msb, rc_lsb; - rc_msb = rang.msb()->evaluate(ent, arc, use_msb); - rc_lsb = rang.lsb()->evaluate(ent, arc, use_lsb); + rc_msb = rang.msb()->evaluate(ent, scope, use_msb); + rc_lsb = rang.lsb()->evaluate(ent, scope, use_lsb); if (rc_msb && rc_lsb) { int asize = (use_msb >= use_lsb) ? (use_msb - use_lsb) + 1 : (use_lsb - use_msb) + 1; out << "{" << asize << "{"; - errors += aggregate_[0].expr->emit(out, ent, arc); + errors += aggregate_[0].expr->emit(out, ent, scope); out << "}}"; } else { out << "{("; @@ -134,7 +134,7 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V out << use_msb; } else { out << "("; - errors += rang.msb()->emit(out, ent, arc); + errors += rang.msb()->emit(out, ent, scope); out << ")"; } if (rc_lsb && use_lsb==0) { @@ -142,11 +142,11 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V out << "-" << use_lsb; } else { out << "-("; - errors += rang.lsb()->emit(out, ent, arc); + errors += rang.lsb()->emit(out, ent, scope); out << ")"; } out << "+1){"; - errors += aggregate_[0].expr->emit(out, ent, arc); + errors += aggregate_[0].expr->emit(out, ent, scope); out << "}}"; } return errors; @@ -158,9 +158,9 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V // Fully calculate the range numbers. int64_t use_msb, use_lsb; bool rc; - rc = rang.msb()->evaluate(ent, arc, use_msb); + rc = rang.msb()->evaluate(ent, scope, use_msb); ivl_assert(*this, rc); - rc = rang.lsb()->evaluate(ent, arc, use_lsb); + rc = rang.lsb()->evaluate(ent, scope, use_lsb); ivl_assert(*this, rc); if(use_msb < use_lsb) swap(use_msb, use_lsb); @@ -198,14 +198,14 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V if (prange_t*range = aggregate_[idx].choice->range_expressions()) { int64_t begin_val, end_val; - if (! range->msb()->evaluate(ent, arc, begin_val)) { + if (! range->msb()->evaluate(ent, scope, begin_val)) { cerr << range->msb()->get_fileline() << ": error: " << "Unable to evaluate aggregate choice expression." << endl; errors += 1; continue; } - if (! range->lsb()->evaluate(ent, arc, end_val)) { + if (! range->lsb()->evaluate(ent, scope, end_val)) { cerr << range->msb()->get_fileline() << ": error: " << "Unable to evaluate aggregate choice expression." << endl; errors += 1; @@ -235,7 +235,7 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V // elements so disable further positional // processing. positional_section = false; - if (! tmp->evaluate(ent, arc, tmp_val)) { + if (! tmp->evaluate(ent, scope, tmp_val)) { cerr << tmp->get_fileline() << ": error: " << "Unable to evaluate aggregate choice expression." << endl; errors += 1; @@ -266,7 +266,7 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V << "Missing element " << idx << "." << endl; errors += 1; } else { - errors += cur->expr->emit(out, ent, arc); + errors += cur->expr->emit(out, ent, scope); } } out << "}"; @@ -274,7 +274,7 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V return errors; } -int ExpAggregate::emit_record_(ostream&out, Entity*ent, Architecture*arc, const VTypeRecord*) +int ExpAggregate::emit_record_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeRecord*) { int errors = 0; @@ -292,9 +292,9 @@ int ExpAggregate::emit_record_(ostream&out, Entity*ent, Architecture*arc, const if(idx != 0) out << ","; - //errors += name->emit(out, ent, arc); + //errors += name->emit(out, ent, scope); //out << ": "; - errors += val->emit(out, ent, arc); + errors += val->emit(out, ent, scope); } out << "}"; @@ -302,13 +302,13 @@ int ExpAggregate::emit_record_(ostream&out, Entity*ent, Architecture*arc, const return errors; } -int ExpAttribute::emit(ostream&out, Entity*ent, Architecture*arc) +int ExpAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; if (name_ == "event") { out << "$ivlh_attribute_event("; - errors += base_->emit(out, ent, arc); + errors += base_->emit(out, ent, scope); out << ")"; return errors; } @@ -319,27 +319,27 @@ int ExpAttribute::emit(ostream&out, Entity*ent, Architecture*arc) expression doesn't even need to be evaluated.) */ if (name_=="length") { out << "$bits("; - errors += base_->emit(out, ent, arc); + errors += base_->emit(out, ent, scope); out << ")"; return errors; } else if (name_=="left" || name_=="right") { out << "$" << name_ << "("; - errors += base_->emit(out, ent, arc); + errors += base_->emit(out, ent, scope); out << ")"; return errors; } out << "$ivl_attribute("; - errors += base_->emit(out, ent, arc); + errors += base_->emit(out, ent, scope); out << ", \"" << name_ << "\")"; return errors; } -int ExpArithmetic::emit(ostream&out, Entity*ent, Architecture*arc) +int ExpArithmetic::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; - errors += emit_operand1(out, ent, arc); + errors += emit_operand1(out, ent, scope); switch (fun_) { case PLUS: @@ -369,12 +369,12 @@ int ExpArithmetic::emit(ostream&out, Entity*ent, Architecture*arc) break; } - errors += emit_operand2(out, ent, arc); + errors += emit_operand2(out, ent, scope); return errors; } -int ExpBitstring::emit(ostream&out, Entity*, Architecture*) +int ExpBitstring::emit(ostream&out, Entity*, ScopeBase*) { int errors = 0; @@ -385,7 +385,7 @@ int ExpBitstring::emit(ostream&out, Entity*, Architecture*) return errors; } -int ExpCharacter::emit_primitive_bit_(ostream&out, Entity*, Architecture*, +int ExpCharacter::emit_primitive_bit_(ostream&out, Entity*, ScopeBase*, const VTypePrimitive*etype) { switch (etype->type()) { @@ -407,17 +407,17 @@ int ExpCharacter::emit_primitive_bit_(ostream&out, Entity*, Architecture*, return 1; } -int ExpCharacter::emit(ostream&out, Entity*ent, Architecture*arc) +int ExpCharacter::emit(ostream&out, Entity*ent, ScopeBase*scope) { const VType*etype = peek_type(); if (const VTypePrimitive*use_type = dynamic_cast(etype)) { - return emit_primitive_bit_(out, ent, arc, use_type); + return emit_primitive_bit_(out, ent, scope, use_type); } if (const VTypeArray*array = dynamic_cast(etype)) { if (const VTypePrimitive*use_type = dynamic_cast(array->element_type())) { - return emit_primitive_bit_(out, ent, arc, use_type); + return emit_primitive_bit_(out, ent, scope, use_type); } } @@ -439,22 +439,22 @@ bool ExpConcat::is_primary(void) const return true; } -int ExpConcat::emit(ostream&out, Entity*ent, Architecture*arc) +int ExpConcat::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; out << "{"; - errors += operand1_->emit(out, ent, arc); + errors += operand1_->emit(out, ent, scope); out << ", "; - errors += operand2_->emit(out, ent, arc); + errors += operand2_->emit(out, ent, scope); out << "}"; return errors; } -int ExpConditional::emit(ostream&out, Entity*ent, Architecture*arc) +int ExpConditional::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; out << "("; - errors += cond_->emit(out, ent, arc); + errors += cond_->emit(out, ent, scope); out << ")? ("; if (true_clause_.size() > 1) { @@ -463,7 +463,7 @@ int ExpConditional::emit(ostream&out, Entity*ent, Architecture*arc) } Expression*tmp = true_clause_.front(); - errors += tmp->emit(out, ent, arc); + errors += tmp->emit(out, ent, scope); out << ") : ("; @@ -475,11 +475,11 @@ int ExpConditional::emit(ostream&out, Entity*ent, Architecture*arc) for (list::iterator cur = else_clause_.begin() ; cur != last ; ++cur) { - errors += (*cur) ->emit_when_else(out, ent, arc); + errors += (*cur) ->emit_when_else(out, ent, scope); } } - errors += else_clause_.back()->emit_else(out, ent, arc); + errors += else_clause_.back()->emit_else(out, ent, scope); out << ")"; // The emit_when_else() functions do not close the last @@ -492,13 +492,13 @@ int ExpConditional::emit(ostream&out, Entity*ent, Architecture*arc) return errors; } -int ExpConditional::else_t::emit_when_else(ostream&out, Entity*ent, Architecture*arc) +int ExpConditional::else_t::emit_when_else(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; assert(cond_ != 0); out << "("; - errors += cond_->emit(out, ent, arc); + errors += cond_->emit(out, ent, scope); out << ")? ("; if (true_clause_.size() > 1) { @@ -507,14 +507,14 @@ int ExpConditional::else_t::emit_when_else(ostream&out, Entity*ent, Architecture } Expression*tmp = true_clause_.front(); - errors += tmp->emit(out, ent, arc); + errors += tmp->emit(out, ent, scope); out << ") : ("; return errors; } -int ExpConditional::else_t::emit_else(ostream&out, Entity*ent, Architecture*arc) +int ExpConditional::else_t::emit_else(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; // Trailing else must have no condition. @@ -526,12 +526,12 @@ int ExpConditional::else_t::emit_else(ostream&out, Entity*ent, Architecture*arc) } Expression*tmp = true_clause_.front(); - errors += tmp->emit(out, ent, arc); + errors += tmp->emit(out, ent, scope); return errors; } -int ExpEdge::emit(ostream&out, Entity*ent, Architecture*arc) +int ExpEdge::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; switch (fun_) { @@ -544,11 +544,11 @@ int ExpEdge::emit(ostream&out, Entity*ent, Architecture*arc) case ANYEDGE: break; } - errors += emit_operand1(out, ent, arc); + errors += emit_operand1(out, ent, scope); return errors; } -int ExpFunc::emit(ostream&out, Entity*ent, Architecture*arc) +int ExpFunc::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; @@ -558,46 +558,46 @@ int ExpFunc::emit(ostream&out, Entity*ent, Architecture*arc) // std numeric library, but we interpret it as the same // as the $unsigned function. out << "$unsigned("; - errors += argv_[0]->emit(out, ent, arc); + errors += argv_[0]->emit(out, ent, scope); out << ")"; } else if (name_ == "integer" && argv_.size() == 1) { - // Simply skip the function name, SystemVerilog takes care of - // rounding real numbers - errors += argv_[0]->emit(out, ent, arc); + out << "$signed("; + errors += argv_[0]->emit(out, ent, scope); + out << ")"; } else if (name_ == "std_logic_vector" && argv_.size() == 1) { // Special case: The std_logic_vector function casts its // argument to std_logic_vector. Internally, we don't // have to do anything for that to work. out << "("; - errors += argv_[0]->emit(out, ent, arc); + errors += argv_[0]->emit(out, ent, scope); out << ")"; } else if (name_ == "to_unsigned" && argv_.size() == 2) { out << "$ivlh_to_unsigned("; - errors += argv_[0]->emit(out, ent, arc); + errors += argv_[0]->emit(out, ent, scope); out << ", "; - errors += argv_[1]->emit(out, ent, arc); + errors += argv_[1]->emit(out, ent, scope); out << ")"; } else if (name_ == "conv_std_logic_vector" && argv_.size() == 2) { int64_t use_size; - bool rc = argv_[1]->evaluate(ent, arc, use_size); + bool rc = argv_[1]->evaluate(ent, scope, use_size); ivl_assert(*this, rc); out << use_size << "'("; - errors += argv_[0]->emit(out, ent, arc); + errors += argv_[0]->emit(out, ent, scope); out << ")"; } else if (name_ == "rising_edge" && argv_.size()==1) { out << "$ivlh_rising_edge("; - errors += argv_[0]->emit(out, ent, arc); + errors += argv_[0]->emit(out, ent, scope); out << ")"; } else if (name_ == "falling_edge" && argv_.size()==1) { out << "$ivlh_falling_edge("; - errors += argv_[0]->emit(out, ent, arc); + errors += argv_[0]->emit(out, ent, scope); out << ")"; } else { @@ -615,7 +615,7 @@ int ExpFunc::emit(ostream&out, Entity*ent, Architecture*arc) out << "\\" << name_ << " ("; for (size_t idx = 0; idx < argv_.size() ; idx += 1) { if (idx > 0) out << ", "; - errors += argv_[idx]->emit(out, ent, arc); + errors += argv_[idx]->emit(out, ent, scope); } out << ")"; } @@ -623,7 +623,7 @@ int ExpFunc::emit(ostream&out, Entity*ent, Architecture*arc) return errors; } -int ExpInteger::emit(ostream&out, Entity*, Architecture*) +int ExpInteger::emit(ostream&out, Entity*, ScopeBase*) { out << value_; return 0; @@ -635,12 +635,7 @@ int ExpInteger::emit_package(ostream&out) return 0; } -bool ExpInteger::is_primary(void) const -{ - return true; -} - -int ExpReal::emit(ostream&out, Entity*, Architecture*) +int ExpReal::emit(ostream&out, Entity*, ScopeBase*) { out << value_; return 0; @@ -657,11 +652,11 @@ bool ExpReal::is_primary(void) const return true; } -int ExpLogical::emit(ostream&out, Entity*ent, Architecture*arc) +int ExpLogical::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; - errors += emit_operand1(out, ent, arc); + errors += emit_operand1(out, ent, scope); switch (fun_) { case AND: @@ -684,22 +679,22 @@ int ExpLogical::emit(ostream&out, Entity*ent, Architecture*arc) break; } - errors += emit_operand2(out, ent, arc); + errors += emit_operand2(out, ent, scope); return errors; } -int ExpName::emit_as_prefix_(ostream&out, Entity*ent, Architecture*arc) +int ExpName::emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; if (prefix_.get()) { - errors += prefix_->emit_as_prefix_(out, ent, arc); + errors += prefix_->emit_as_prefix_(out, ent, scope); } out << "\\" << name_ << " "; if (index_) { out << "["; - errors += index_->emit(out, ent, arc); + errors += index_->emit(out, ent, scope); out << "]"; ivl_assert(*this, lsb_ == 0); } @@ -707,27 +702,28 @@ int ExpName::emit_as_prefix_(ostream&out, Entity*ent, Architecture*arc) return errors; } -int ExpName::emit(ostream&out, Entity*ent, Architecture*arc) +int ExpName::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; if (prefix_.get()) { - errors += prefix_->emit_as_prefix_(out, ent, arc); + errors += prefix_->emit_as_prefix_(out, ent, scope); } const GenerateStatement*gs = 0; + Architecture*arc = dynamic_cast(scope); if (arc && (gs = arc->probe_genvar_emit(name_))) - out << "\\" << gs->get_name() << ":" << name_ << " "; + out << "\\" << gs->get_name() << ":" << name_ << " "; else out << "\\" << name_ << " "; if (index_) { out << "["; - errors += index_->emit(out, ent, arc); + errors += index_->emit(out, ent, scope); if (lsb_) { out << ":"; - errors += lsb_->emit(out, ent, arc); + errors += lsb_->emit(out, ent, scope); } out << "]"; } @@ -740,10 +736,10 @@ bool ExpName::is_primary(void) const return true; } -int ExpRelation::emit(ostream&out, Entity*ent, Architecture*arc) +int ExpRelation::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; - errors += emit_operand1(out, ent, arc); + errors += emit_operand1(out, ent, scope); switch (fun_) { case EQ: @@ -766,7 +762,7 @@ int ExpRelation::emit(ostream&out, Entity*ent, Architecture*arc) break; } - errors += emit_operand2(out, ent, arc); + errors += emit_operand2(out, ent, scope); return errors; } @@ -775,13 +771,13 @@ bool ExpString::is_primary(void) const return true; } -int ExpString::emit(ostream& out, Entity*ent, Architecture*arc) +int ExpString::emit(ostream& out, Entity*ent, ScopeBase*scope) { const VType*type = peek_type(); assert(type != 0); if (const VTypeArray*arr = dynamic_cast(type)) { - return emit_as_array_(out, ent, arc, arr); + return emit_as_array_(out, ent, scope, arr); } out << "\""; @@ -792,7 +788,7 @@ int ExpString::emit(ostream& out, Entity*ent, Architecture*arc) return 0; } -int ExpString::emit_as_array_(ostream& out, Entity*, Architecture*, const VTypeArray*arr) +int ExpString::emit_as_array_(ostream& out, Entity*, ScopeBase*, const VTypeArray*arr) { int errors = 0; assert(arr->dimensions() == 1); @@ -843,20 +839,39 @@ int ExpString::emit_as_array_(ostream& out, Entity*, Architecture*, const VTypeA return errors; } -int ExpUAbs::emit(ostream&out, Entity*ent, Architecture*arc) +int ExpUAbs::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; out << "abs("; - errors += emit_operand1(out, ent, arc); + errors += emit_operand1(out, ent, scope); out << ")"; return errors; } -int ExpUNot::emit(ostream&out, Entity*ent, Architecture*arc) +int ExpUNot::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; out << "~("; - errors += emit_operand1(out, ent, arc); + errors += emit_operand1(out, ent, scope); out << ")"; return errors; } + +int ExpCast::emit(ostream&out, Entity*ent, ScopeBase*scope) +{ + int errors = 0; + errors += type_->emit_def(out, empty_perm_string); + out << "'("; + errors += base_->emit(out, ent, scope); + out << ")"; + return errors; +} + +int ExpNew::emit(ostream&out, Entity*ent, ScopeBase*scope) +{ + int errors = 0; + out << "new["; + errors += size_->emit(out, ent, scope); + out << "]"; + return errors; +} diff --git a/vhdlpp/expression_evaluate.cc b/vhdlpp/expression_evaluate.cc index 2f506eb28..d53c707f3 100644 --- a/vhdlpp/expression_evaluate.cc +++ b/vhdlpp/expression_evaluate.cc @@ -1,5 +1,7 @@ /* * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2015 + * @author 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 @@ -26,9 +28,9 @@ bool Expression::evaluate(ScopeBase*, int64_t&) const return false; } -bool Expression::evaluate(Entity*, Architecture*arc, int64_t&val) const +bool Expression::evaluate(Entity*, ScopeBase*scope, int64_t&val) const { - return evaluate(arc, val); + return evaluate(scope, val); } @@ -76,18 +78,31 @@ bool ExpArithmetic::evaluate(ScopeBase*scope, int64_t&val) const return true; } -bool ExpAttribute::evaluate(ScopeBase*, int64_t&val) const +bool ExpAttribute::evaluate(ScopeBase*scope, int64_t&val) const { - /* Special Case: The length attribute can be calculated all + /* Special Case: The array attributes can sometimes 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") { + if (name_ == "length" || name_ == "right" || name_ == "left") { const VType*base_type = base_->peek_type(); - //if (base_type == 0) - // base_type = base_->probe_type(ent,arc); - ivl_assert(*this, base_type); + if(!base_type) { + const ExpName*name = NULL; + + if(scope && (name = dynamic_cast(base_))) { + const perm_string& n = name->peek_name(); + if(const Variable*var = scope->find_variable(n)) + base_type = var->peek_type(); + else if(const Signal*sig = scope->find_signal(n)) + base_type = sig->peek_type(); + else if(const InterfacePort*port = scope->find_param(n)) + base_type = port->type; + } + } + + if(!base_type) + return false; // I tried really hard, sorry const VTypeArray*arr = dynamic_cast(base_type); if (arr == 0) { @@ -97,25 +112,43 @@ bool ExpAttribute::evaluate(ScopeBase*, int64_t&val) const 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; + 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; + + 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; + } else if(name_ == "left") { + arr->dimension(0).msb()->evaluate(scope, val); + } else if(name_ == "right") { + arr->dimension(0).lsb()->evaluate(scope, val); + } else ivl_assert(*this, false); + return true; } return false; } -bool ExpAttribute::evaluate(Entity*ent, Architecture*arc, int64_t&val) const +bool ExpAttribute::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const { + if (!ent || !scope) { // it's impossible to evaluate, probably it is inside a subprogram + return false; + } + if (name_ == "left" || name_ == "right") { const VType*base_type = base_->peek_type(); if (base_type == 0) - base_type = base_->probe_type(ent,arc); + base_type = base_->probe_type(ent, scope); ivl_assert(*this, base_type); @@ -129,14 +162,14 @@ bool ExpAttribute::evaluate(Entity*ent, Architecture*arc, int64_t&val) const 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); + arr->dimension(0).msb()->evaluate(ent, scope, val); + else // "right" + arr->dimension(0).lsb()->evaluate(ent, scope, val); return true; } - return evaluate(arc, val); + return evaluate(scope, val); } /* @@ -165,7 +198,7 @@ bool ExpName::evaluate(ScopeBase*scope, int64_t&val) const return exp->evaluate(scope, val); } -bool ExpName::evaluate(Entity*ent, Architecture*arc, int64_t&val) const +bool ExpName::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const { if (prefix_.get()) { cerr << get_fileline() << ": sorry: I don't know how to evaluate ExpName prefix parts." << endl; @@ -178,8 +211,8 @@ bool ExpName::evaluate(Entity*ent, Architecture*arc, int64_t&val) const // Evaluate the default expression and use that. if (gen->expr) - return gen->expr->evaluate(ent, arc, val); + return gen->expr->evaluate(ent, scope, val); } - return evaluate(arc, val); + return evaluate(scope, val); } diff --git a/vhdlpp/expression_stream.cc b/vhdlpp/expression_stream.cc index 103e210ae..5c682a5cd 100644 --- a/vhdlpp/expression_stream.cc +++ b/vhdlpp/expression_stream.cc @@ -24,7 +24,7 @@ using namespace std; -void ExpAggregate::write_to_stream(ostream&fd) +void ExpAggregate::write_to_stream(ostream&fd) const { fd << "("; for (vector::const_iterator cur = elements_.begin() @@ -73,7 +73,7 @@ void ExpAggregate::choice_t::write_to_stream(ostream&fd) fd << "/* ERROR */"; } -void ExpArithmetic::write_to_stream(ostream&out) +void ExpArithmetic::write_to_stream(ostream&out) const { out << "("; write_to_stream_operand1(out); @@ -111,23 +111,23 @@ void ExpArithmetic::write_to_stream(ostream&out) out << ")"; } -void ExpAttribute::write_to_stream(ostream&fd) +void ExpAttribute::write_to_stream(ostream&fd) const { base_->write_to_stream(fd); fd << "'" << name_; } -void ExpBitstring::write_to_stream(ostream&fd) +void ExpBitstring::write_to_stream(ostream&fd) const { - fd << "\""; - for(vector::const_iterator it = value_.begin(); - it != value_.end(); ++it) { + fd << "B\""; + for(vector::const_reverse_iterator it = value_.rbegin(); + it != value_.rend(); ++it) { fd << *it; } fd << "\""; } -void ExpCharacter::write_to_stream(ostream&fd) +void ExpCharacter::write_to_stream(ostream&fd) const { char buf[4]; buf[0] = '\''; @@ -137,7 +137,7 @@ void ExpCharacter::write_to_stream(ostream&fd) fd << buf; } -void ExpConcat::write_to_stream(ostream&fd) +void ExpConcat::write_to_stream(ostream&fd) const { fd << "("; operand1_->write_to_stream(fd); @@ -146,21 +146,21 @@ void ExpConcat::write_to_stream(ostream&fd) fd << ")"; } -void ExpConditional::write_to_stream(ostream&) +void ExpConditional::write_to_stream(ostream&) const { ivl_assert(*this, !"Not supported"); } -void ExpEdge::write_to_stream(ostream&) +void ExpEdge::write_to_stream(ostream&) const { ivl_assert(*this, !"Not supported"); } -void ExpFunc::write_to_stream(ostream&fd) +void ExpFunc::write_to_stream(ostream&fd) const { const char*comma = ""; fd << name_ << "("; - for (vector::iterator cur = argv_.begin() + for (vector::const_iterator cur = argv_.begin() ; cur != argv_.end() ; ++cur) { fd << comma; (*cur)->write_to_stream(fd); @@ -169,22 +169,22 @@ void ExpFunc::write_to_stream(ostream&fd) fd << ")"; } -void ExpInteger::write_to_stream(ostream&fd) +void ExpInteger::write_to_stream(ostream&fd) const { fd << value_; } -void ExpReal::write_to_stream(ostream&fd) +void ExpReal::write_to_stream(ostream&fd) const { fd << value_; } -void ExpLogical::write_to_stream(ostream&) +void ExpLogical::write_to_stream(ostream&) const { ivl_assert(*this, !"Not supported"); } -void ExpName::write_to_stream(ostream&fd) +void ExpName::write_to_stream(ostream&fd) const { if (prefix_.get()) { prefix_->write_to_stream(fd); @@ -203,12 +203,40 @@ void ExpName::write_to_stream(ostream&fd) } } -void ExpRelation::write_to_stream(ostream&) +void ExpRelation::write_to_stream(ostream&fd) const { - ivl_assert(*this, !"Not supported"); + peek_operand1()->write_to_stream(fd); + + switch(fun_) { + case EQ: + fd << " = "; + break; + + case LT: + fd << " < "; + break; + + case GT: + fd << " > "; + break; + + case NEQ: + fd << " != "; + break; + + case LE: + fd << " <= "; + break; + + case GE: + fd << " >= "; + break; + } + + peek_operand2()->write_to_stream(fd); } -void ExpString::write_to_stream(ostream&fd) +void ExpString::write_to_stream(ostream&fd) const { fd << "\""; for(vector::const_iterator it = value_.begin(); @@ -218,15 +246,21 @@ void ExpString::write_to_stream(ostream&fd) fd << "\""; } -void ExpUAbs::write_to_stream(ostream&fd) +void ExpUAbs::write_to_stream(ostream&fd) const { fd << "abs "; write_to_stream_operand1(fd); } -void ExpUNot::write_to_stream(ostream&fd) +void ExpUNot::write_to_stream(ostream&fd) const { fd << "not "; write_to_stream_operand1(fd); } +void ExpCast::write_to_stream(ostream&fd) const +{ + // Type casting is introduced only for a few specific cases in + // SystemVerilog, so no need to use it here + base_->write_to_stream(fd); +} diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index 3ed27b0e2..1eb5fc54f 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -430,13 +430,10 @@ void library_set_work_path(const char*path) library_work_path = path; } +list work_packages; static void store_package_in_work(const Package*pack) { - string path = make_work_package_path(pack->name()); - - ofstream file (path.c_str(), ios_base::out); - - pack->write_to_stream(file); + work_packages.push_back(pack); } static int emit_packages(perm_string, const map&packages) @@ -447,6 +444,13 @@ static int emit_packages(perm_string, const map&packages) errors += cur->second->emit_package(cout); } + for (list::const_iterator cur = work_packages.begin() + ; cur != work_packages.end(); ++cur) { + string path = make_work_package_path((*cur)->name()); + ofstream file (path.c_str(), ios_base::out); + (*cur)->write_to_stream(file); + } + return errors; } diff --git a/vhdlpp/package.cc b/vhdlpp/package.cc index 9c0025f47..240eb37a1 100644 --- a/vhdlpp/package.cc +++ b/vhdlpp/package.cc @@ -130,4 +130,11 @@ void Package::write_to_stream(ostream&fd) const } fd << "end package " << name_ << ";" << endl; + + fd << "package body " << name_ << " is" << endl; + for (map::const_iterator cur = cur_subprograms_.begin() + ; cur != cur_subprograms_.end() ; ++cur) { + cur->second->write_to_stream_body(fd); + } + fd << "end " << name_ << ";" << endl; } diff --git a/vhdlpp/package_emit.cc b/vhdlpp/package_emit.cc index 94a40c8c8..42ce821a9 100644 --- a/vhdlpp/package_emit.cc +++ b/vhdlpp/package_emit.cc @@ -49,7 +49,8 @@ int Package::emit_package(ostream&fd) const for (map::const_iterator cur = cur_types_.begin() ; cur != cur_types_.end() ; ++ cur) { fd << "typedef "; - errors += cur->second->emit_def(fd, cur->first); + errors += cur->second->emit_def(fd, + dynamic_cast(cur->second) ? empty_perm_string : cur->first); fd << " ;" << endl; } @@ -68,7 +69,9 @@ int Package::emit_package(ostream&fd) const for (map::const_iterator cur = cur_subprograms_.begin() ; cur != cur_subprograms_.end() ; ++ cur) { - errors += cur->second->emit_package(fd); + // Do not emit unbounded functions, we will just need fixed instances later + if(!cur->second->unbounded()) + errors += cur->second->emit_package(fd); } fd << "endpackage" << endl; diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index ecde6b0b2..a509d8fa6 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -573,20 +573,40 @@ case_statement_alternative_list * statement alternative and pass that up instead. */ case_statement_alternative - : K_when choice ARROW sequence_of_statements + : K_when choices ARROW sequence_of_statements { CaseSeqStmt::CaseStmtAlternative* tmp; - if ($2->others()) { - tmp = new CaseSeqStmt::CaseStmtAlternative(0, $4); - } else if (Expression*ex = $2->simple_expression()) { - tmp = new CaseSeqStmt::CaseStmtAlternative(ex, $4); - } else { - errormsg(@2, "I don't know what to make of the case choice\n"); - tmp = 0; - } - if (tmp) FILE_NAME(tmp, @1); - delete $2; - delete $4; - $$ = tmp; + std::list*choices = $2; + std::list*exp_list = new std::list; + bool others = false; + + for(std::list::iterator it = choices->begin(); + it != choices->end(); ++it) { + if((*it)->others() || others) + // If there is one "others", then it also covers all other alternatives + // Continue the loop to delete every choice_t, but do not + // bother to add the expressions to the exp_list (we are going to + // delete them very soon) + others = true; + else + exp_list->push_back((*it)->simple_expression()); + + delete (*it); + } + + if(others) { + tmp = new CaseSeqStmt::CaseStmtAlternative(0, $4); + for(std::list::iterator it = exp_list->begin(); + it != exp_list->end(); ++it) { + delete (*it); + } + } else { + tmp = new CaseSeqStmt::CaseStmtAlternative(exp_list, $4); + } + if (tmp) FILE_NAME(tmp, @1); + + delete choices; + delete $4; + $$ = tmp; } ; @@ -2504,9 +2524,9 @@ K_postponed_opt : K_postponed | ; K_shared_opt : K_shared | ; %% -static void yyerror(YYLTYPE*, yyscan_t, const char*, bool, const char* /*msg*/) +static void yyerror(YYLTYPE*loc, yyscan_t, const char*, bool, const char*msg) { - //fprintf(stderr, "%s\n", msg); + fprintf(stderr, "%s:%u: %s\n", loc->text, loc->first_line, msg); parse_errors += 1; } diff --git a/vhdlpp/parse_misc.cc b/vhdlpp/parse_misc.cc index 734443d3e..f49a631c3 100644 --- a/vhdlpp/parse_misc.cc +++ b/vhdlpp/parse_misc.cc @@ -105,6 +105,7 @@ static const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_n VTypeArray*subtype = new VTypeArray(element, range, base_array->signed_vector()); + subtype->set_parent_type(base_array); return subtype; } diff --git a/vhdlpp/parse_types.h b/vhdlpp/parse_types.h index 625312762..3639a9c1f 100644 --- a/vhdlpp/parse_types.h +++ b/vhdlpp/parse_types.h @@ -72,6 +72,9 @@ class prange_t { public: prange_t(Expression* left, Expression* right, bool dir) : left_(left), right_(right), direction_(dir), auto_dir_(false) {} + prange_t(const prange_t&other) : + left_(other.left_->clone()), right_(other.right_->clone()), + direction_(other.direction_), auto_dir_(other.auto_dir_) {} ~prange_t() { delete left_; delete right_; } void dump(ostream&out, int indent) const; @@ -91,7 +94,6 @@ class prange_t { bool auto_dir_; private: //not implemented - prange_t(const prange_t&); prange_t operator=(const prange_t&); }; diff --git a/vhdlpp/scope.cc b/vhdlpp/scope.cc index 5182aee1a..eac3ece1e 100644 --- a/vhdlpp/scope.cc +++ b/vhdlpp/scope.cc @@ -21,6 +21,7 @@ # include "scope.h" # include "package.h" # include "subprogram.h" +# include "entity.h" # include # include # include @@ -148,6 +149,23 @@ Variable* ScopeBase::find_variable(perm_string by_name) const } } +const InterfacePort* ScopeBase::find_param(perm_string by_name) const +{ + for(map::const_iterator it = use_subprograms_.begin(); + it != use_subprograms_.end(); ++it) { + if(const InterfacePort*port = it->second->find_param(by_name)) + return port; + } + + for(map::const_iterator it = cur_subprograms_.begin(); + it != cur_subprograms_.end(); ++it) { + if(const InterfacePort*port = it->second->find_param(by_name)) + return port; + } + + return NULL; +} + Subprogram* ScopeBase::find_subprogram(perm_string name) const { map::const_iterator cur; diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index 2b0fdc5b3..6bb7ed4e5 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -56,11 +56,19 @@ class ScopeBase { bool find_constant(perm_string by_name, const VType*&typ, Expression*&exp); 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; Subprogram* find_subprogram(perm_string by_name) const; // Moves all signals, variables and components from another scope to // this one. After the transfer new_* maps are emptied in the another scope. void transfer_from(ScopeBase&ref); + inline void bind_subprogram(perm_string name, Subprogram*obj) + { map::iterator it; + if((it = use_subprograms_.find(name)) != use_subprograms_.end() ) + use_subprograms_.erase(it); + cur_subprograms_[name] = obj; + } + protected: void cleanup(); diff --git a/vhdlpp/sequential.cc b/vhdlpp/sequential.cc index 9d5d8d6e3..f6fe41d0d 100644 --- a/vhdlpp/sequential.cc +++ b/vhdlpp/sequential.cc @@ -19,6 +19,15 @@ # include "sequential.h" # include "expression.h" +# include + +template +inline static void visit_stmt_list(std::list& stmts, SeqStmtVisitor& func) +{ + for(typename std::list::iterator it = stmts.begin(); it != stmts.end(); ++it) { + (*it)->visit(func); + } +} SequentialStmt::SequentialStmt() { @@ -75,6 +84,14 @@ void IfSequential::extract_false(std::list&that) } } +void IfSequential::visit(SeqStmtVisitor& func) +{ + visit_stmt_list(if_, func); + visit_stmt_list(elsif_, func); + visit_stmt_list(else_, func); + func(this); +} + IfSequential::Elsif::Elsif(Expression*cond, std::list*tr) : cond_(cond) { @@ -91,6 +108,11 @@ IfSequential::Elsif::~Elsif() } } +void IfSequential::Elsif::visit(SeqStmtVisitor& func) +{ + visit_stmt_list(if_, func); +} + SignalSeqAssignment::SignalSeqAssignment(Expression*sig, std::list*wav) { lval_ = sig; @@ -118,7 +140,14 @@ CaseSeqStmt::~CaseSeqStmt() } } -CaseSeqStmt::CaseStmtAlternative::CaseStmtAlternative(Expression* exp, list* stmts) +void CaseSeqStmt::visit(SeqStmtVisitor& func) +{ + visit_stmt_list(alt_, func); + func(this); +} + +CaseSeqStmt::CaseStmtAlternative::CaseStmtAlternative(std::list*exp, + list*stmts) : exp_(exp) { if (stmts) stmts_.splice(stmts_.end(), *stmts); @@ -134,6 +163,11 @@ CaseSeqStmt::CaseStmtAlternative::~CaseStmtAlternative() } } +void CaseSeqStmt::CaseStmtAlternative::visit(SeqStmtVisitor& func) +{ + visit_stmt_list(stmts_, func); +} + ProcedureCall::ProcedureCall(perm_string name) : name_(name), param_list_(0) { @@ -163,6 +197,12 @@ ReturnStmt::~ReturnStmt() delete val_; } +void ReturnStmt::cast_to(const VType*type) +{ + assert(val_); + val_ = new ExpCast(val_, type); +} + LoopStatement::LoopStatement(perm_string name, list* stmts) : name_(name) { @@ -178,6 +218,12 @@ LoopStatement::~LoopStatement() } } +void LoopStatement::visit(SeqStmtVisitor& func) +{ + visit_stmt_list(stmts_, func); + func(this); +} + ForLoopStatement::ForLoopStatement(perm_string scope_name, perm_string it, prange_t* range, list* stmts) : LoopStatement(scope_name, stmts), it_(it), range_(range) { diff --git a/vhdlpp/sequential.h b/vhdlpp/sequential.h index 9271e4ed3..c9f039fea 100644 --- a/vhdlpp/sequential.h +++ b/vhdlpp/sequential.h @@ -23,10 +23,17 @@ # include "LineInfo.h" # include "parse_types.h" # include +# include -class Architecture; +class ScopeBase; class Entity; class Expression; +class SequentialStmt; + +struct SeqStmtVisitor { + virtual ~SeqStmtVisitor() {}; + virtual void operator() (SequentialStmt*s) = 0; +}; class SequentialStmt : public LineInfo { @@ -35,9 +42,13 @@ class SequentialStmt : public LineInfo { virtual ~SequentialStmt() =0; public: - virtual int elaborate(Entity*ent, Architecture*arc); - virtual int emit(ostream&out, Entity*entity, Architecture*arc); + virtual int elaborate(Entity*ent, ScopeBase*scope); + virtual int emit(ostream&out, Entity*entity, ScopeBase*scope); virtual void dump(ostream&out, int indent) const; + virtual void write_to_stream(std::ostream&fd); + + // Recursively visits a tree of sequential statements. + virtual void visit(SeqStmtVisitor& func) { func(this); } }; /* @@ -52,10 +63,12 @@ class LoopStatement : public SequentialStmt { inline perm_string loop_name() const { return name_; } void dump(ostream&out, int indent) const; + void visit(SeqStmtVisitor& func); protected: - int elaborate_substatements(Entity*ent, Architecture*arc); - int emit_substatements(std::ostream&out, Entity*ent, Architecture*arc); + int elaborate_substatements(Entity*ent, ScopeBase*scope); + int emit_substatements(std::ostream&out, Entity*ent, ScopeBase*scope); + void write_to_stream_substatements(ostream&fd); private: perm_string name_; @@ -70,11 +83,15 @@ class IfSequential : public SequentialStmt { Elsif(Expression*cond, std::list*tr); ~Elsif(); - int elaborate(Entity*entity, Architecture*arc); - int condition_emit(ostream&out, Entity*entity, Architecture*arc); - int statement_emit(ostream&out, Entity*entity, Architecture*arc); + int elaborate(Entity*entity, ScopeBase*scope); + int condition_emit(ostream&out, Entity*entity, ScopeBase*scope); + int statement_emit(ostream&out, Entity*entity, ScopeBase*scope); + + void condition_write_to_stream(ostream&fd); + void statement_write_to_stream(ostream&fd); void dump(ostream&out, int indent) const; + void visit(SeqStmtVisitor& func); private: Expression*cond_; @@ -91,9 +108,11 @@ class IfSequential : public SequentialStmt { ~IfSequential(); public: - int elaborate(Entity*ent, Architecture*arc); - int emit(ostream&out, Entity*entity, Architecture*arc); + int elaborate(Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*entity, ScopeBase*scope); + void write_to_stream(std::ostream&fd); void dump(ostream&out, int indent) const; + void visit(SeqStmtVisitor& func); const Expression*peek_condition() const { return cond_; } @@ -117,10 +136,12 @@ class ReturnStmt : public SequentialStmt { ~ReturnStmt(); public: - int emit(ostream&out, Entity*entity, Architecture*arc); + int emit(ostream&out, Entity*entity, ScopeBase*scope); + void write_to_stream(std::ostream&fd); void dump(ostream&out, int indent) const; const Expression*peek_expr() const { return val_; }; + void cast_to(const VType*type); private: Expression*val_; @@ -132,8 +153,9 @@ class SignalSeqAssignment : public SequentialStmt { ~SignalSeqAssignment(); public: - int elaborate(Entity*ent, Architecture*arc); - int emit(ostream&out, Entity*entity, Architecture*arc); + int elaborate(Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*entity, ScopeBase*scope); + void write_to_stream(std::ostream&fd); void dump(ostream&out, int indent) const; private: @@ -145,15 +167,17 @@ class CaseSeqStmt : public SequentialStmt { public: class CaseStmtAlternative : public LineInfo { public: - CaseStmtAlternative(Expression* exp, std::list* stmts); + CaseStmtAlternative(std::list*exp, std::list*stmts); ~CaseStmtAlternative(); void dump(std::ostream& out, int indent) const; - int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); - int elaborate(Entity*ent, Architecture*arc); - int emit(ostream&out, Entity*entity, Architecture*arc); + int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); + int elaborate(Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*entity, ScopeBase*scope); + void write_to_stream(std::ostream&fd); + void visit(SeqStmtVisitor& func); private: - Expression* exp_; + std::list*exp_; std::list stmts_; private: // not implemented CaseStmtAlternative(const CaseStmtAlternative&); @@ -166,8 +190,10 @@ class CaseSeqStmt : public SequentialStmt { public: void dump(ostream&out, int indent) const; - int elaborate(Entity*ent, Architecture*arc); - int emit(ostream&out, Entity*entity, Architecture*arc); + int elaborate(Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*entity, ScopeBase*scope); + void write_to_stream(std::ostream&fd); + void visit(SeqStmtVisitor& func); private: Expression* cond_; @@ -180,8 +206,8 @@ class ProcedureCall : public SequentialStmt { ProcedureCall(perm_string name, std::list* param_list); ~ProcedureCall(); - int elaborate(Entity*ent, Architecture*arc); - int emit(ostream&out, Entity*entity, Architecture*arc); + int elaborate(Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*entity, ScopeBase*scope); void dump(ostream&out, int indent) const; private: @@ -195,8 +221,9 @@ class VariableSeqAssignment : public SequentialStmt { ~VariableSeqAssignment(); public: - int elaborate(Entity*ent, Architecture*arc); - int emit(ostream&out, Entity*entity, Architecture*arc); + int elaborate(Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*entity, ScopeBase*scope); + void write_to_stream(std::ostream&fd); void dump(ostream&out, int indent) const; private: @@ -210,8 +237,7 @@ class WhileLoopStatement : public LoopStatement { ExpLogical*, list*); ~WhileLoopStatement(); - int elaborate(Entity*ent, Architecture*arc); - int emit(ostream&out, Entity*entity, Architecture*arc); + int elaborate(Entity*ent, ScopeBase*scope); void dump(ostream&out, int indent) const; private: @@ -224,11 +250,16 @@ class ForLoopStatement : public LoopStatement { perm_string index, prange_t*, list*); ~ForLoopStatement(); - int elaborate(Entity*ent, Architecture*arc); - int emit(ostream&out, Entity*entity, Architecture*arc); + int elaborate(Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope); + void write_to_stream(std::ostream&fd); void dump(ostream&out, int indent) const; private: + // Emits for-loop which direction is determined at run-time. + // It is used for 'range & 'reverse_range attributes. + int emit_runtime_(ostream&out, Entity*ent, ScopeBase*scope); + perm_string it_; prange_t* range_; }; @@ -238,8 +269,7 @@ class BasicLoopStatement : public LoopStatement { BasicLoopStatement(perm_string lname, list*); ~BasicLoopStatement(); - int elaborate(Entity*ent, Architecture*arc); - int emit(ostream&out, Entity*entity, Architecture*arc); + int elaborate(Entity*ent, ScopeBase*scope); void dump(ostream&out, int indent) const; }; diff --git a/vhdlpp/sequential_debug.cc b/vhdlpp/sequential_debug.cc index b28d0f8cc..31f3655d2 100644 --- a/vhdlpp/sequential_debug.cc +++ b/vhdlpp/sequential_debug.cc @@ -105,7 +105,9 @@ void CaseSeqStmt::CaseStmtAlternative::dump(ostream& out, int indent) const out << setw(indent) << "" << "when "; if (exp_) - exp_->dump(out, 0); + for (list::iterator it = exp_->begin(); it != exp_->end(); ++it) { + (*it)->dump(out, 0); + } else out << "others" << endl; diff --git a/vhdlpp/sequential_elaborate.cc b/vhdlpp/sequential_elaborate.cc index 184f85d56..29b4e4914 100644 --- a/vhdlpp/sequential_elaborate.cc +++ b/vhdlpp/sequential_elaborate.cc @@ -20,35 +20,35 @@ # include "sequential.h" # include "expression.h" -int SequentialStmt::elaborate(Entity*, Architecture*) +int SequentialStmt::elaborate(Entity*, ScopeBase*) { return 0; } -int LoopStatement::elaborate_substatements(Entity*ent, Architecture*arc) +int LoopStatement::elaborate_substatements(Entity*ent, ScopeBase*scope) { int errors = 0; for (list::iterator cur = stmts_.begin() ; cur != stmts_.end() ; ++cur) { - errors += (*cur)->elaborate(ent, arc); + errors += (*cur)->elaborate(ent, scope); } return errors; } -int CaseSeqStmt::elaborate(Entity*ent, Architecture*arc) +int CaseSeqStmt::elaborate(Entity*ent, ScopeBase*scope) { int errors = 0; - const VType*ctype = cond_->probe_type(ent, arc); - errors += cond_->elaborate_expr(ent, arc, ctype); + const VType*ctype = cond_->probe_type(ent, scope); + errors += cond_->elaborate_expr(ent, scope, ctype); for (list::iterator cur = alt_.begin() ; cur != alt_.end() ; ++cur) { CaseStmtAlternative*curp = *cur; - errors += curp->elaborate_expr(ent, arc, ctype); - errors += curp->elaborate(ent, arc); + errors += curp->elaborate_expr(ent, scope, ctype); + errors += curp->elaborate(ent, scope); } return errors; @@ -59,79 +59,82 @@ int CaseSeqStmt::elaborate(Entity*ent, Architecture*arc) * ltype is the probed type for the main case condition. The * expression needs to elaborate itself in that context. */ -int CaseSeqStmt::CaseStmtAlternative::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) +int CaseSeqStmt::CaseStmtAlternative::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) { int errors = 0; - if (exp_) - errors += exp_->elaborate_expr(ent, arc, ltype); + if (exp_) { + for (list::iterator it = exp_->begin(); it != exp_->end(); + ++it) { + errors += (*it)->elaborate_expr(ent, scope, ltype); + } + } return errors; } -int CaseSeqStmt::CaseStmtAlternative::elaborate(Entity*ent, Architecture*arc) +int CaseSeqStmt::CaseStmtAlternative::elaborate(Entity*ent, ScopeBase*scope) { int errors = 0; for (list::iterator cur = stmts_.begin() ; cur != stmts_.end() ; ++cur) { SequentialStmt*curp = *cur; - errors += curp->elaborate(ent, arc); + errors += curp->elaborate(ent, scope); } return errors; } - -int ForLoopStatement::elaborate(Entity*ent, Architecture*arc) +int ForLoopStatement::elaborate(Entity*ent, ScopeBase*scope) { int errors = 0; - errors += elaborate_substatements(ent, arc); + errors += elaborate_substatements(ent, scope); return errors; } -int IfSequential::elaborate(Entity*ent, Architecture*arc) +int IfSequential::elaborate(Entity*ent, ScopeBase*scope) { int errors = 0; - errors += cond_->elaborate_expr(ent, arc, 0); + errors += cond_->elaborate_expr(ent, scope, 0); for (list::iterator cur = if_.begin() ; cur != if_.end() ; ++cur) { - errors += (*cur)->elaborate(ent, arc); + errors += (*cur)->elaborate(ent, scope); } for (list::iterator cur = elsif_.begin() ; cur != elsif_.end() ; ++cur) { - errors += (*cur)->elaborate(ent, arc); + errors += (*cur)->elaborate(ent, scope); } for (list::iterator cur = else_.begin() ; cur != else_.end() ; ++cur) { - errors += (*cur)->elaborate(ent, arc); + errors += (*cur)->elaborate(ent, scope); } return errors; } -int IfSequential::Elsif::elaborate(Entity*ent, Architecture*arc) +int IfSequential::Elsif::elaborate(Entity*ent, ScopeBase*scope) { int errors = 0; - errors += cond_->elaborate_expr(ent, arc, 0); + errors += cond_->elaborate_expr(ent, scope, 0); for (list::iterator cur = if_.begin() ; cur != if_.end() ; ++cur) { - errors += (*cur)->elaborate(ent, arc); + errors += (*cur)->elaborate(ent, scope); } return errors; } -int SignalSeqAssignment::elaborate(Entity*ent, Architecture*arc) +int SignalSeqAssignment::elaborate(Entity*ent, ScopeBase*scope) { int errors = 0; // Elaborate the l-value expression. - errors += lval_->elaborate_lval(ent, arc, true); + errors += lval_->elaborate_lval(ent, scope, true); // The elaborate_lval should have resolved the type of the // l-value expression. We'll use that type to elaborate the @@ -146,23 +149,23 @@ int SignalSeqAssignment::elaborate(Entity*ent, Architecture*arc) for (list::iterator cur = waveform_.begin() ; cur != waveform_.end() ; ++cur) { - errors += (*cur)->elaborate_expr(ent, arc, lval_type); + errors += (*cur)->elaborate_expr(ent, scope, lval_type); } return errors; } -int ProcedureCall::elaborate(Entity*, Architecture*) +int ProcedureCall::elaborate(Entity*, ScopeBase*) { return 0; } -int VariableSeqAssignment::elaborate(Entity*ent, Architecture*arc) +int VariableSeqAssignment::elaborate(Entity*ent, ScopeBase*scope) { int errors = 0; // Elaborate the l-value expression. - errors += lval_->elaborate_lval(ent, arc, true); + errors += lval_->elaborate_lval(ent, scope, true); // The elaborate_lval should have resolved the type of the // l-value expression. We'll use that type to elaborate the @@ -174,18 +177,18 @@ int VariableSeqAssignment::elaborate(Entity*ent, Architecture*arc) } // Elaborate the r-value expression. - errors += rval_->elaborate_expr(ent, arc, lval_type); + errors += rval_->elaborate_expr(ent, scope, lval_type); return errors; } -int WhileLoopStatement::elaborate(Entity*, Architecture*) +int WhileLoopStatement::elaborate(Entity*, ScopeBase*) { //TODO:check whether there is any wait statement in the statements (there should be) return 0; } -int BasicLoopStatement::elaborate(Entity*, Architecture*) +int BasicLoopStatement::elaborate(Entity*, ScopeBase*) { return 0; } diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index 86a9a529c..895d1d839 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -1,6 +1,8 @@ /* * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) + * Copyright CERN 2015 + * @author 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 @@ -27,7 +29,7 @@ # include # include -int SequentialStmt::emit(ostream&out, Entity*, Architecture*) +int SequentialStmt::emit(ostream&out, Entity*, ScopeBase*) { out << " // " << get_fileline() << ": internal error: " << "I don't know how to emit this sequential statement! " @@ -35,23 +37,30 @@ int SequentialStmt::emit(ostream&out, Entity*, Architecture*) return 1; } -int IfSequential::emit(ostream&out, Entity*ent, Architecture*arc) +void SequentialStmt::write_to_stream(std::ostream&fd) +{ + fd << " // " << get_fileline() << ": internal error: " + << "I don't know how to write_to_stream this sequential statement! " + << "type=" << typeid(*this).name() << endl; +} + +int IfSequential::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; out << "if ("; - errors += cond_->emit(out, ent, arc); + errors += cond_->emit(out, ent, scope); out << ") begin" << endl; for (list::iterator cur = if_.begin() ; cur != if_.end() ; ++cur) - errors += (*cur)->emit(out, ent, arc); + errors += (*cur)->emit(out, ent, scope); for (list::iterator cur = elsif_.begin() ; cur != elsif_.end() ; ++cur) { out << "end else if ("; - errors += (*cur)->condition_emit(out, ent, arc); + errors += (*cur)->condition_emit(out, ent, scope); out << ") begin" << endl; - errors += (*cur)->statement_emit(out, ent, arc); + errors += (*cur)->statement_emit(out, ent, scope); } if (! else_.empty()) { @@ -59,7 +68,7 @@ int IfSequential::emit(ostream&out, Entity*ent, Architecture*arc) for (list::iterator cur = else_.begin() ; cur != else_.end() ; ++cur) - errors += (*cur)->emit(out, ent, arc); + errors += (*cur)->emit(out, ent, scope); } @@ -67,36 +76,84 @@ int IfSequential::emit(ostream&out, Entity*ent, Architecture*arc) return errors; } -int IfSequential::Elsif::condition_emit(ostream&out, Entity*ent, Architecture*arc) +void IfSequential::write_to_stream(std::ostream&fd) { - return cond_->emit(out, ent, arc); + fd << "if "; + cond_->write_to_stream(fd); + fd << " then " << endl; + + for (list::iterator cur = if_.begin() + ; cur != if_.end() ; ++cur) + (*cur)->write_to_stream(fd); + + for (list::iterator cur = elsif_.begin() + ; cur != elsif_.end() ; ++cur) { + fd << "elsif "; + (*cur)->condition_write_to_stream(fd); + fd << " " << endl; + (*cur)->statement_write_to_stream(fd); + } + + if (! else_.empty()) { + fd << " else " << endl; + + for (list::iterator cur = else_.begin() + ; cur != else_.end() ; ++cur) + (*cur)->write_to_stream(fd); + } + + fd << "end if;" << endl; } -int IfSequential::Elsif::statement_emit(ostream&out, Entity*ent, Architecture*arc) +int IfSequential::Elsif::condition_emit(ostream&out, Entity*ent, ScopeBase*scope) +{ + return cond_->emit(out, ent, scope); +} + +int IfSequential::Elsif::statement_emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; for (list::iterator cur = if_.begin() ; cur != if_.end() ; ++cur) - errors += (*cur)->emit(out, ent, arc); + errors += (*cur)->emit(out, ent, scope); return errors; } -int ReturnStmt::emit(ostream&out, Entity*ent, Architecture*arc) +void IfSequential::Elsif::condition_write_to_stream(ostream&fd) +{ + cond_->write_to_stream(fd); +} + +void IfSequential::Elsif::statement_write_to_stream(ostream&fd) +{ + for (list::iterator cur = if_.begin() + ; cur != if_.end() ; ++cur) + (*cur)->write_to_stream(fd); +} + +int ReturnStmt::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; out << "return "; - errors += val_->emit(out, ent, arc); + errors += val_->emit(out, ent, scope); out << ";" << endl; return errors; } -int SignalSeqAssignment::emit(ostream&out, Entity*ent, Architecture*arc) +void ReturnStmt::write_to_stream(ostream&fd) +{ + fd << "return "; + val_->write_to_stream(fd); + fd << ";" << endl; +} + +int SignalSeqAssignment::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; - errors += lval_->emit(out, ent, arc); + errors += lval_->emit(out, ent, scope); if (waveform_.size() != 1) { out << "/* Confusing waveform? */;" << endl; @@ -105,27 +162,50 @@ int SignalSeqAssignment::emit(ostream&out, Entity*ent, Architecture*arc) } else { Expression*tmp = waveform_.front(); out << " <= "; - errors += tmp->emit(out, ent, arc); + errors += tmp->emit(out, ent, scope); out << ";" << endl; } return errors; } -int VariableSeqAssignment::emit(ostream&out, Entity*ent, Architecture*arc) +void SignalSeqAssignment::write_to_stream(ostream&fd) +{ + lval_->write_to_stream(fd); + + if (waveform_.size() != 1) { + fd << "-- Confusing waveform?" << endl; + + } else { + Expression*tmp = waveform_.front(); + fd << " <= "; + tmp->write_to_stream(fd); + fd << ";" << endl; + } +} + +int VariableSeqAssignment::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; - errors += lval_->emit(out, ent, arc); + errors += lval_->emit(out, ent, scope); out << " = "; - errors += rval_->emit(out, ent, arc); + errors += rval_->emit(out, ent, scope); out << ";" << endl; return errors; } -int ProcedureCall::emit(ostream&out, Entity*, Architecture*) +void VariableSeqAssignment::write_to_stream(ostream&fd) +{ + lval_->write_to_stream(fd); + fd << " := "; + rval_->write_to_stream(fd); + fd << ";" << endl; +} + +int ProcedureCall::emit(ostream&out, Entity*, ScopeBase*) { out << " // " << get_fileline() << ": internal error: " << "I don't know how to emit this sequential statement! " @@ -133,29 +213,38 @@ int ProcedureCall::emit(ostream&out, Entity*, Architecture*) return 1; } -int LoopStatement::emit_substatements(ostream&out, Entity*ent, Architecture*arc) +int LoopStatement::emit_substatements(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; for (list::iterator cur = stmts_.begin() ; cur != stmts_.end() ; ++cur) { SequentialStmt*tmp = *cur; - errors += tmp->emit(out, ent, arc); + errors += tmp->emit(out, ent, scope); } return errors; } -int CaseSeqStmt::emit(ostream&out, Entity*ent, Architecture*arc) +void LoopStatement::write_to_stream_substatements(ostream&fd) +{ + for (list::iterator cur = stmts_.begin() + ; cur != stmts_.end() ; ++cur) { + SequentialStmt*tmp = *cur; + tmp->write_to_stream(fd); + } +} + +int CaseSeqStmt::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; out << "case ("; - errors += cond_->emit(out, ent, arc); + errors += cond_->emit(out, ent, scope); out << ")" << endl; for (list::iterator cur = alt_.begin() ; cur != alt_.end() ; ++cur) { CaseStmtAlternative*curp = *cur; - errors += curp ->emit(out, ent, arc); + errors += curp ->emit(out, ent, scope); } out << "endcase" << endl; @@ -163,16 +252,38 @@ int CaseSeqStmt::emit(ostream&out, Entity*ent, Architecture*arc) return errors; } -int CaseSeqStmt::CaseStmtAlternative::emit(ostream&out, Entity*ent, Architecture*arc) +void CaseSeqStmt::write_to_stream(ostream&fd) +{ + fd << "case "; + cond_->write_to_stream(fd); + fd << " is" << endl; + + for (list::iterator cur = alt_.begin() + ; cur != alt_.end() ; ++cur) { + CaseStmtAlternative*curp = *cur; + curp ->write_to_stream(fd); + } + + fd << "end case;" << endl; +} + +int CaseSeqStmt::CaseStmtAlternative::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; + bool first = true; if (exp_) { - errors += exp_->emit(out, ent, arc); - out << ":" << endl; + for (list::iterator it = exp_->begin(); it != exp_->end(); ++it) { + if(first) + first = false; + else + out << ","; + errors += (*it)->emit(out, ent, scope); + } } else { - out << "default:" << endl; + out << "default"; } + out << ":" << endl; SequentialStmt*curp; @@ -182,14 +293,14 @@ int CaseSeqStmt::CaseStmtAlternative::emit(ostream&out, Entity*ent, Architecture break; case 1: curp = stmts_.front(); - errors += curp->emit(out, ent, arc); + errors += curp->emit(out, ent, scope); break; default: out << "begin" << endl; for (list::iterator cur = stmts_.begin() ; cur != stmts_.end() ; ++cur) { curp = *cur; - errors += curp->emit(out, ent, arc); + errors += curp->emit(out, ent, scope); } out << "end" << endl; break; @@ -198,92 +309,145 @@ int CaseSeqStmt::CaseStmtAlternative::emit(ostream&out, Entity*ent, Architecture return errors; } -int ForLoopStatement::emit(ostream&out, Entity*ent, Architecture*arc) +void CaseSeqStmt::CaseStmtAlternative::write_to_stream(ostream&fd) { - int errors = 0; - ivl_assert(*this, range_); + fd << "when "; + if (exp_) { + bool first = true; + for (list::iterator it = exp_->begin(); it != exp_->end(); ++it) { + if(first) + first = false; + else + fd << "|"; - int64_t start_val; - bool start_rc = range_->msb()->evaluate(ent, arc, start_val); - - int64_t finish_val; - bool finish_rc = range_->lsb()->evaluate(ent, arc, finish_val); - - ivl_assert(*this, start_rc); - ivl_assert(*this, finish_rc); - - bool dir = range_->is_downto(); - - if (!dir) { - int64_t tmp = start_val; - start_val = finish_val; - finish_val = tmp; + (*it)->write_to_stream(fd); + } + } else { + fd << "others" << endl; } + fd << "=>" << endl; - if (dir && (start_val < finish_val)) { - if(range_->is_auto_dir()) { - dir = false; - } else { - out << "begin /* Degenerate loop at " << get_fileline() - << ": " << start_val - << " downto " << finish_val << " */ end" << endl; - return errors; - } + for (list::iterator cur = stmts_.begin() + ; cur != stmts_.end() ; ++cur) { + (*cur)->write_to_stream(fd); } - - else if (!dir && start_val > finish_val) { - if(range_->is_auto_dir()) { - dir = true; - } else { - out << "begin /* Degenerate loop at " << get_fileline() - << ": " << start_val - << " to " << finish_val << " */ end" << endl; - return errors; - } - } - - perm_string scope_name = loop_name(); - if (scope_name.nil()) { - char buf[80]; - snprintf(buf, sizeof buf, "__%p", this); - scope_name = lex_strings.make(buf); - } - - out << "begin : " << scope_name << endl; - out << "longint \\" << it_ << " ;" << endl; - out << "for (\\" << it_ << " = " << start_val << " ; "; - if (dir) - out << "\\" << it_ << " >= " << finish_val; - else - out << "\\" << it_ << " <= " << finish_val; - out << "; \\" << it_ << " = \\" << it_; - if (dir) - out << " - 1"; - else - out << " + 1"; - - out << ") begin" << endl; - - errors += emit_substatements(out, ent, arc); - - out << "end" << endl; - out << "end /* " << scope_name << " */" << endl; - - return errors; } -int WhileLoopStatement::emit(ostream&out, Entity*, Architecture*) +int ForLoopStatement::emit(ostream&out, Entity*ent, ScopeBase*scope) { - out << " // " << get_fileline() << ": internal error: " - << "I don't know how to emit this sequential statement! " - << "type=" << typeid(*this).name() << endl; - return 1; + int errors = 0; + ivl_assert(*this, range_); + + int64_t start_val; + bool start_rc = range_->msb()->evaluate(ent, scope, start_val); + + int64_t finish_val; + bool finish_rc = range_->lsb()->evaluate(ent, scope, finish_val); + + perm_string scope_name = loop_name(); + if (scope_name.nil()) { + char buf[80]; + snprintf(buf, sizeof buf, "__%p", this); + scope_name = lex_strings.make(buf); + } + + out << "begin : " << scope_name << endl; + out << "longint \\" << it_ << " ;" << endl; + + if(!start_rc || !finish_rc) { + // Could not evaluate one of the loop boundaries, it has to be + // determined during the run-time + errors += emit_runtime_(out, ent, scope); + } else { + bool dir = range_->is_downto(); + + if (!dir) { + int64_t tmp = start_val; + start_val = finish_val; + finish_val = tmp; + } + + if (dir && (start_val < finish_val)) { + if(range_->is_auto_dir()) { + dir = false; + } else { + out << "begin /* Degenerate loop at " << get_fileline() + << ": " << start_val + << " downto " << finish_val << " */ end" << endl + << "end" << endl; + return errors; + } + } + + else if (!dir && start_val > finish_val) { + if(range_->is_auto_dir()) { + dir = true; + } else { + out << "begin /* Degenerate loop at " << get_fileline() + << ": " << start_val + << " to " << finish_val << " */ end" << endl + << "end" << endl; + return errors; + } + } + + out << "for (\\" << it_ << " = " << start_val << " ; "; + + if (dir) + out << "\\" << it_ << " >= " << finish_val; + else + out << "\\" << it_ << " <= " << finish_val; + + out << "; \\" << it_ << " = \\" << it_; + + if (dir) + out << " - 1)"; + else + out << " + 1)"; + } + + out << " begin" << endl; + + errors += emit_substatements(out, ent, scope); + + out << "end" << endl; + out << "end /* " << scope_name << " */" << endl; + + return errors; } -int BasicLoopStatement::emit(ostream&out, Entity*, Architecture*) +void ForLoopStatement::write_to_stream(ostream&fd) { - out << " // " << get_fileline() << ": internal error: " - << "I don't know how to emit this sequential statement! " - << "type=" << typeid(*this).name() << endl; - return 1; + fd << "for " << it_ << " in "; + range_->expr_left()->write_to_stream(fd); + fd << " to "; + range_->expr_right()->write_to_stream(fd); + fd << " loop" << endl; + write_to_stream_substatements(fd); + fd << "end loop;" << endl; +} + +int ForLoopStatement::emit_runtime_(ostream&out, Entity*ent, ScopeBase*scope) +{ + int errors = 0; + + out << "for (\\" << it_ << " = "; + errors += range_->expr_left()->emit(out, ent, scope); + + // Twisted way of determining the loop direction at runtime + out << " ;\n("; + errors += range_->expr_left()->emit(out, ent, scope); + out << " < "; + errors += range_->expr_right()->emit(out, ent, scope); + out << " ? \\" << it_ << " <= "; + errors += range_->expr_right()->emit(out, ent, scope); + out << " : \\" << it_ << " >= "; + errors += range_->expr_right()->emit(out, ent, scope); + out << ");\n\\" << it_ << " = \\" << it_ << " + ("; + errors += range_->expr_left()->emit(out, ent, scope); + out << " < "; + errors += range_->expr_right()->emit(out, ent, scope); + out << " ? 1 : -1))"; + + return errors; } diff --git a/vhdlpp/subprogram.cc b/vhdlpp/subprogram.cc index 5814bfdbf..8d2f4f814 100644 --- a/vhdlpp/subprogram.cc +++ b/vhdlpp/subprogram.cc @@ -1,6 +1,8 @@ /* * Copyright (c) 2013-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) + * Copyright CERN 2015 + * @author 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 @@ -23,6 +25,8 @@ # include "vtype.h" # include "sequential.h" # include "ivl_assert.h" +# include "compiler.h" +# include using namespace std; @@ -46,7 +50,21 @@ void Subprogram::set_program_body(list*stmt) { ivl_assert(*this, statements_==0); statements_ = stmt; - fix_return_type(); +} + +bool Subprogram::unbounded() const { + if(return_type_->is_unbounded()) + return true; + + if(ports_) { + for(std::list::const_iterator it = ports_->begin(); + it != ports_->end(); ++it) { + if((*it)->type->is_unbounded()) + return true; + } + } + + return false; } bool Subprogram::compare_specification(Subprogram*that) const @@ -105,30 +123,104 @@ const VType*Subprogram::peek_param_type(int idx) const return (*p)->type; } -void Subprogram::fix_return_type(void) -{ - if(!statements_) - return; +Subprogram*Subprogram::make_instance(std::vector arguments, ScopeBase*scope) { + assert(arguments.size() == ports_->size()); - const ReturnStmt*ret = NULL; - const VType*t = NULL; + std::list*ports = new std::list; + int i = 0; - for (std::list::const_iterator s = statements_->begin() - ; s != statements_->end(); ++s) { - if((ret = dynamic_cast(*s))) { + // Change the argument types to match the ones that were used during + // the function call + for(std::list::iterator it = ports_->begin(); + it != ports_->end(); ++it) { + InterfacePort*p = new InterfacePort(**it); + p->type = arguments[i++]->peek_type()->clone(); + assert(p->type); + ports->push_back(p); + } + + char buf[80]; + snprintf(buf, sizeof(buf), "__%s_%p", name_.str(), ports); + perm_string new_name = lex_strings.make(buf); + Subprogram*instance = new Subprogram(new_name, ports, return_type_); + + // Copy variables + for(std::map::iterator it = new_variables_.begin(); + it != new_variables_.end(); ++it) { + Variable*v = new Variable(it->first, it->second->peek_type()->clone()); + instance->new_variables_[it->first] = v; + } + + instance->set_parent(scope); + instance->set_program_body(statements_); + instance->fix_return_type(); + scope->bind_subprogram(new_name, instance); + + return instance; +} + +struct check_return_type : public SeqStmtVisitor { + check_return_type(const Subprogram*subp) : subp_(subp), ret_type_(NULL) {} + + void operator() (SequentialStmt*s) + { + ReturnStmt*ret; + if((ret = dynamic_cast(s))) { const Expression*expr = ret->peek_expr(); + const VType*t = NULL; if(const ExpName*n = dynamic_cast(expr)) { - if(Variable*v = find_variable(n->peek_name())) + if(Variable*v = subp_->find_variable(n->peek_name())) t = v->peek_type(); } else { t = expr->peek_type(); } - if(t) - return_type_ = t; + if(!t) { // cannot determine the type at least in one case + ret_type_ = NULL; + return; + } + + if(!ret_type_) { // this is first processed return statement + ret_type_ = t; + } else if(!t->type_match(ret_type_)) { + // the function can return different types, + // we cannot have fixed width + ret_type_ = NULL; + return; + } } } + + const VType*get_type() const { return ret_type_; } + +private: + const Subprogram*subp_; + const VType*ret_type_; +}; + +void Subprogram::fix_return_type() +{ + if(!statements_) + return; + + check_return_type r(this); + + for (std::list::iterator s = statements_->begin() + ; s != statements_->end(); ++s) { + (*s)->visit(r); + } + + VType*return_type = const_cast(r.get_type()); + if(return_type && !return_type->is_unbounded()) { + // Let's check if the variable length can be evaluated without any scope. + // If not, then it is depends on information about e.g. function params + if(return_type->is_variable_length(NULL)) { + if(VTypeArray*arr = dynamic_cast(return_type)) + arr->evaluate_ranges(this); + } + return_type_ = return_type; + } } void Subprogram::write_to_stream(ostream&fd) const @@ -149,3 +241,39 @@ void Subprogram::write_to_stream(ostream&fd) const return_type_->write_to_stream(fd); fd << ";" << endl; } + +void Subprogram::write_to_stream_body(ostream&fd) const +{ + fd << "function " << name_ << "("; + if (ports_ && ! ports_->empty()) { + list::const_iterator cur = ports_->begin(); + InterfacePort*curp = *cur; + fd << curp->name << " : "; + curp->type->write_to_stream(fd); + for (++cur ; cur != ports_->end() ; ++cur) { + curp = *cur; + fd << "; " << curp->name << " : "; + curp->type->write_to_stream(fd); + } + } + fd << ") return "; + return_type_->write_to_stream(fd); + fd << " is" << endl; + + for (map::const_iterator cur = new_variables_.begin() + ; cur != new_variables_.end() ; ++cur) { + cur->second->write_to_stream(fd); + } + + fd << "begin" << endl; + + if (statements_) { + for (list::const_iterator cur = statements_->begin() + ; cur != statements_->end() ; ++cur) { + (*cur)->write_to_stream(fd); + } + } else { + fd << "--empty body" << endl; + } + fd << "end function;" << endl; +} diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h index 5b38f1223..22c49879e 100644 --- a/vhdlpp/subprogram.h +++ b/vhdlpp/subprogram.h @@ -3,6 +3,8 @@ /* * Copyright (c) 2013-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) + * Copyright CERN 2015 + * @author 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 @@ -43,6 +45,7 @@ class Subprogram : public LineInfo, public ScopeBase { inline const perm_string&name() const { return name_; } void set_program_body(std::list*statements); + inline bool empty_program_body() const { return !statements_ || statements_->empty(); } // Return true if the specification (name, types, ports) // matches this subprogram and that subprogram. @@ -50,19 +53,31 @@ class Subprogram : public LineInfo, public ScopeBase { const InterfacePort*find_param(perm_string nam) const; const VType*peek_param_type(int idx) const; + const VType*peek_return_type() const { return return_type_; } - int emit(ostream&out, Entity*ent, Architecture*arc); + int emit(ostream&out, Entity*ent, ScopeBase*scope); // Emit a definition as it would show up in a package. int emit_package(std::ostream&fd) const; void write_to_stream(std::ostream&fd) const; + void write_to_stream_body(std::ostream&fd) const; void dump(std::ostream&fd) const; + // Creates a new instance of the function that takes arguments of + // a different type. It is used to allow VHDL functions that work with + // unbounded std_logic_vectors, so there can be a separate instance + // for limited length logic vector. + Subprogram*make_instance(std::vector arguments, ScopeBase*scope); + + // Checks if either return type or parameters are unbounded vectors. + bool unbounded() const; + private: - // Determines appropriate return type. Un case of std_logic_vector - // VHDL requires skipping its size in contrary to Verilog - void fix_return_type(void); + // Tries to set the return type to a fixed type. VHDL functions that + // return std_logic_vectors do not specify its length, as SystemVerilog + // demands. + void fix_return_type(); perm_string name_; const ScopeBase*parent_; diff --git a/vhdlpp/subprogram_emit.cc b/vhdlpp/subprogram_emit.cc index 6f1b37508..5cb43e3a6 100644 --- a/vhdlpp/subprogram_emit.cc +++ b/vhdlpp/subprogram_emit.cc @@ -70,7 +70,7 @@ int Subprogram::emit_package(ostream&fd) const if (statements_) { for (list::const_iterator cur = statements_->begin() ; cur != statements_->end() ; ++cur) { - errors += (*cur)->emit(fd, NULL, NULL); + errors += (*cur)->emit(fd, NULL, const_cast(this)); } } else { fd << " begin /* empty body */ end" << endl; diff --git a/vhdlpp/vsignal.cc b/vhdlpp/vsignal.cc index e8bc87a35..94bd8959b 100644 --- a/vhdlpp/vsignal.cc +++ b/vhdlpp/vsignal.cc @@ -34,10 +34,10 @@ SigVarBase::~SigVarBase() { } -void SigVarBase::elaborate_init_expr(Entity*ent, Architecture*arc) +void SigVarBase::elaborate_init_expr(Entity*ent, ScopeBase*scope) { if(init_expr_) { - init_expr_->elaborate_expr(ent, arc, peek_type()); + init_expr_->elaborate_expr(ent, scope, peek_type()); } } @@ -46,7 +46,7 @@ void SigVarBase::type_elaborate_(VType::decl_t&decl) decl.type = type_; } -int Signal::emit(ostream&out, Entity*ent, Architecture*arc) +int Signal::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; @@ -54,18 +54,18 @@ int Signal::emit(ostream&out, Entity*ent, Architecture*arc) type_elaborate_(decl); if (peek_refcnt_sequ_() > 0 || !peek_type()->can_be_packed()) decl.reg_flag = true; - errors += decl.emit(out, peek_name_()); + errors += decl.emit(out, peek_name()); Expression*init_expr = peek_init_expr(); if (init_expr) { out << " = "; - init_expr->emit(out, ent, arc); + init_expr->emit(out, ent, scope); } out << ";" << endl; return errors; } -int Variable::emit(ostream&out, Entity*, Architecture*) +int Variable::emit(ostream&out, Entity*, ScopeBase*) { int errors = 0; @@ -73,7 +73,14 @@ int Variable::emit(ostream&out, Entity*, Architecture*) type_elaborate_(decl); if (peek_refcnt_sequ_() > 0 || !peek_type()->can_be_packed()) decl.reg_flag = true; - errors += decl.emit(out, peek_name_()); + errors += decl.emit(out, peek_name()); out << ";" << endl; return errors; } + +void Variable::write_to_stream(std::ostream&fd) +{ + fd << "variable " << peek_name() << " : "; + peek_type()->write_to_stream(fd); + fd << ";" << endl; +} diff --git a/vhdlpp/vsignal.h b/vhdlpp/vsignal.h index 9d97e3b0f..d2bfdbcd0 100644 --- a/vhdlpp/vsignal.h +++ b/vhdlpp/vsignal.h @@ -24,6 +24,7 @@ # include "vtype.h" class Architecture; +class ScopeBase; class Entity; class Expression; @@ -42,10 +43,11 @@ class SigVarBase : public LineInfo { void dump(ostream&out, int indent = 0) const; // Elaborates initializer expressions if needed. - void elaborate_init_expr(Entity*ent, Architecture*arc); + void elaborate_init_expr(Entity*ent, ScopeBase*scope); + + perm_string peek_name() const { return name_; } protected: - perm_string peek_name_() const { return name_; } unsigned peek_refcnt_sequ_() const { return refcnt_sequ_; } void type_elaborate_(VType::decl_t&decl); @@ -69,7 +71,7 @@ class Signal : public SigVarBase { public: Signal(perm_string name, const VType*type, Expression*init_expr); - int emit(ostream&out, Entity*ent, Architecture*arc); + int emit(ostream&out, Entity*ent, ScopeBase*scope); }; class Variable : public SigVarBase { @@ -77,7 +79,8 @@ class Variable : public SigVarBase { public: Variable(perm_string name, const VType*type); - int emit(ostream&out, Entity*ent, Architecture*arc); + int emit(ostream&out, Entity*ent, ScopeBase*scope); + void write_to_stream(std::ostream&fd); }; inline void SigVarBase::count_ref_sequ() diff --git a/vhdlpp/vtype.cc b/vhdlpp/vtype.cc index a7f9233aa..4a05d82aa 100644 --- a/vhdlpp/vtype.cc +++ b/vhdlpp/vtype.cc @@ -19,13 +19,13 @@ # include "vtype.h" # include "parse_types.h" +# include "compiler.h" # include # include # include using namespace std; - VType::~VType() { } @@ -35,6 +35,13 @@ void VType::show(ostream&out) const write_to_stream(out); } +perm_string VType::get_generic_typename() const +{ + char buf[16] = {0,}; + snprintf(buf, 16, "type_%p", this); + return lex_strings.make(buf); +} + VTypePrimitive::VTypePrimitive(VTypePrimitive::type_t tt, bool packed) : type_(tt), packed_(packed) { @@ -68,8 +75,13 @@ void VTypePrimitive::show(ostream&out) const } } +VTypeArray::range_t*VTypeArray::range_t::clone() const +{ + return new VTypeArray::range_t(safe_clone(msb_), safe_clone(lsb_), direction_); +} + VTypeArray::VTypeArray(const VType*element, const vector&r, bool sv) -: etype_(element), ranges_(r), signed_flag_(sv) +: etype_(element), ranges_(r), signed_flag_(sv), parent_(NULL) { } @@ -81,7 +93,7 @@ VTypeArray::VTypeArray(const VType*element, const vector&r, * this is a memory leak. Something to fix. */ VTypeArray::VTypeArray(const VType*element, std::list*r, bool sv) -: etype_(element), ranges_(r->size()), signed_flag_(sv) +: etype_(element), ranges_(r->size()), signed_flag_(sv), parent_(NULL) { for (size_t idx = 0 ; idx < ranges_.size() ; idx += 1) { prange_t*curp = r->front(); @@ -98,6 +110,18 @@ VTypeArray::~VTypeArray() { } +VType*VTypeArray::clone() const { + std::vector new_ranges; + new_ranges.reserve(ranges_.size()); + for(std::vector::const_iterator it = ranges_.begin(); + it != ranges_.end(); ++it) { + new_ranges.push_back(*(it->clone())); + } + VTypeArray*a = new VTypeArray(etype_->clone(), new_ranges, signed_flag_); + a->set_parent_type(parent_); + return a; +} + const VType* VTypeArray::basic_type(bool typedef_allowed) const { const VType*t = etype_; @@ -148,6 +172,49 @@ void VTypeArray::show(ostream&out) const out << ""; } +bool VTypeArray::is_unbounded() const { + for(std::vector::const_iterator it = ranges_.begin(); + it != ranges_.end(); ++it) + { + if(it->is_box()) + return true; + } + + return etype_->is_unbounded(); +} + +bool VTypeArray::is_variable_length(ScopeBase*scope) const { + int64_t dummy; + + if(is_unbounded()) + return true; + + for(std::vector::const_iterator it = ranges_.begin(); + it != ranges_.end(); ++it) + { + if(!it->lsb()->evaluate(scope, dummy)) + return true; + + if(!it->msb()->evaluate(scope, dummy)) + return true; + } + + return etype_->is_variable_length(scope); +} + +void VTypeArray::evaluate_ranges(ScopeBase*scope) { + for(std::vector::iterator it = ranges_.begin(); it != ranges_.end(); ++it ) { + int64_t lsb_val = -1, msb_val = -1; + bool dir = it->is_downto(); + + if(it->msb()->evaluate(scope, msb_val) && it->lsb()->evaluate(scope, lsb_val)) { + assert(lsb_val >= 0); + assert(msb_val >= 0); + *it = range_t(new ExpInteger(msb_val), new ExpInteger(lsb_val), dir); + } + } +} + VTypeRange::VTypeRange(const VType*base, int64_t max_val, int64_t min_val) : base_(base) { diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index 580cf92b9..595ca381c 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -30,10 +30,12 @@ # include "StringHeap.h" class Architecture; +class ScopeBase; class Entity; class Expression; class prange_t; class VTypeDef; +class ScopeBase; typedef enum typedef_topo_e { NONE=0, PENDING, MARKED } typedef_topo_t; typedef std::map typedef_context_t; @@ -49,9 +51,11 @@ class VType { VType() { } virtual ~VType() =0; + virtual VType*clone() const =0; + // This is rarely used, but some types may have expressions // that need to be elaborated. - virtual int elaborate(Entity*end, Architecture*arc) const; + virtual int elaborate(Entity*end, ScopeBase*scope) const; // This virtual method returns true if that is equivalent to // this type. This method is used for example to compare @@ -85,6 +89,17 @@ class VType { // Determines if a type can be used in Verilog packed array. virtual bool can_be_packed() const { return false; } + // Returns true if the type has an undefined dimension. + virtual bool is_unbounded() const { return false; } + + // Checks if the variable length is dependent on other expressions, that + // cannot be evaluated (e.g. 'length, 'left, 'right). + virtual bool is_variable_length(ScopeBase*) const { return false; } + + // Returns a perm_string that can be used in automatically created + // typedefs (i.e. not ones defined by the user). + perm_string get_generic_typename() const; + private: friend struct decl_t; // This virtual method is called to emit the declaration. This @@ -123,6 +138,8 @@ extern void preload_global_types(void); * This type is a placeholder for ERROR types. */ class VTypeERROR : public VType { + VType*clone() const { return NULL; } + public: int emit_def(std::ostream&out, perm_string name) const; }; @@ -140,6 +157,8 @@ class VTypePrimitive : public VType { VTypePrimitive(type_t tt, bool packed = false); ~VTypePrimitive(); + VType*clone() const { return new VTypePrimitive(*this); } + void write_to_stream(std::ostream&fd) const; void show(std::ostream&) const; @@ -176,6 +195,8 @@ class VTypeArray : public VType { range_t(Expression*m = NULL, Expression*l = NULL, bool dir = true) : msb_(m), lsb_(l), direction_(dir) { } + range_t*clone() const; + inline bool is_box() const { return msb_==0 && lsb_==0; } inline bool is_downto() const { return direction_; } @@ -193,7 +214,9 @@ class VTypeArray : public VType { VTypeArray(const VType*etype, std::list*r, bool signed_vector =false); ~VTypeArray(); - int elaborate(Entity*ent, Architecture*arc) const; + VType*clone() const; + + int elaborate(Entity*ent, ScopeBase*scope) const; void write_to_stream(std::ostream&fd) const; void write_type_to_stream(std::ostream&fd) const; void show(std::ostream&) const; @@ -205,7 +228,7 @@ class VTypeArray : public VType { inline bool signed_vector() const { return signed_flag_; } // returns the type of element held in the array - inline const VType* element_type() const { return etype_; } + inline const VType* element_type() const { return parent_ ? parent_->element_type() : etype_; } // returns the basic type of element held in the array // (unfolds typedefs and multidimensional arrays) @@ -215,16 +238,29 @@ class VTypeArray : public VType { int emit_def(std::ostream&out, perm_string name) const; int emit_typedef(std::ostream&out, typedef_context_t&ctx) const; - int emit_dimensions(std::ostream&out) const; bool can_be_packed() const { return etype_->can_be_packed(); } - private: - void write_range_to_stream_(std::ostream&fd) const; - const VType*etype_; + bool is_unbounded() const; + bool is_variable_length(ScopeBase*scope) const; + + // To handle subtypes + inline void set_parent_type(const VTypeArray*parent) { parent_ = parent; } + + // Wherever it is possible, replaces range lsb & msb expressions with + // constant integers. + void evaluate_ranges(ScopeBase*scope); + + private: + int emit_with_dims_(std::ostream&out, bool packed, perm_string name) const; + + void write_range_to_stream_(std::ostream&fd) const; + + const VType*etype_; std::vector ranges_; bool signed_flag_; + const VTypeArray*parent_; }; class VTypeRange : public VType { @@ -233,6 +269,8 @@ class VTypeRange : public VType { VTypeRange(const VType*base, int64_t max_val, int64_t min_val); ~VTypeRange(); + VType*clone() const { return new VTypeRange(base_->clone(), max_, min_); } + // Get the type that is limited by the range. inline const VType* base_type() const { return base_; } @@ -251,6 +289,8 @@ class VTypeEnum : public VType { VTypeEnum(const std::list*names); ~VTypeEnum(); + VType*clone() const { return new VTypeEnum(*this); } + void write_to_stream(std::ostream&fd) const; void show(std::ostream&) const; int emit_def(std::ostream&out, perm_string name) const; @@ -284,6 +324,8 @@ class VTypeRecord : public VType { explicit VTypeRecord(std::list*elements); ~VTypeRecord(); + VType*clone() const { return new VTypeRecord(*this); } + void write_to_stream(std::ostream&fd) const; void show(std::ostream&) const; int emit_def(std::ostream&out, perm_string name) const; @@ -302,6 +344,8 @@ class VTypeDef : public VType { explicit VTypeDef(perm_string name, const VType*is); ~VTypeDef(); + VType*clone() const { return new VTypeDef(*this); } + inline perm_string peek_name() const { return name_; } // If the type is not given a definition in the constructor, @@ -319,6 +363,8 @@ class VTypeDef : public VType { int emit_def(std::ostream&out, perm_string name) const; bool can_be_packed() const { return type_->can_be_packed(); } + + bool is_unbounded() const { return type_->is_unbounded(); } private: int emit_decl(std::ostream&out, perm_string name, bool reg_flag) const; diff --git a/vhdlpp/vtype_elaborate.cc b/vhdlpp/vtype_elaborate.cc index f3611d9f4..b3b4cfd9d 100644 --- a/vhdlpp/vtype_elaborate.cc +++ b/vhdlpp/vtype_elaborate.cc @@ -21,24 +21,24 @@ # include "vtype.h" # include "expression.h" -int VType::elaborate(Entity*, Architecture*) const +int VType::elaborate(Entity*, ScopeBase*) const { return 0; } -int VTypeArray::elaborate(Entity*ent, Architecture*arc) const +int VTypeArray::elaborate(Entity*ent, ScopeBase*scope) const { int errors = 0; - etype_->elaborate(ent, arc); + etype_->elaborate(ent, scope); for (vector::const_iterator cur = ranges_.begin() ; cur != ranges_.end() ; ++ cur) { Expression*tmp = cur->msb(); - if (tmp) errors += tmp->elaborate_expr(ent, arc, 0); + if (tmp) errors += tmp->elaborate_expr(ent, scope, 0); tmp = cur->lsb(); - if (tmp) errors += tmp->elaborate_expr(ent, arc, 0); + if (tmp) errors += tmp->elaborate_expr(ent, scope, 0); } return errors; diff --git a/vhdlpp/vtype_emit.cc b/vhdlpp/vtype_emit.cc index aa24dd362..7675568f9 100644 --- a/vhdlpp/vtype_emit.cc +++ b/vhdlpp/vtype_emit.cc @@ -59,9 +59,7 @@ int VTypeERROR::emit_def(ostream&out, perm_string) const int VTypeArray::emit_def(ostream&out, perm_string name) const { int errors = 0; - const VType*raw_base = basic_type(); - const VTypePrimitive*base = dynamic_cast (raw_base); if (base) { @@ -74,13 +72,7 @@ int VTypeArray::emit_def(ostream&out, perm_string name) const raw_base->emit_def(out, empty_perm_string); } - if(raw_base->can_be_packed()) { - errors += emit_dimensions(out); - emit_name(out, name); - } else { - emit_name(out, name); - errors += emit_dimensions(out); - } + errors += emit_with_dims_(out, raw_base->can_be_packed(), name); return errors; } @@ -90,7 +82,7 @@ int VTypeArray::emit_typedef(std::ostream&out, typedef_context_t&ctx) const return etype_->emit_typedef(out, ctx); } -int VTypeArray::emit_dimensions(std::ostream&out) const +int VTypeArray::emit_with_dims_(std::ostream&out, bool packed, perm_string name) const { int errors = 0; @@ -102,18 +94,35 @@ int VTypeArray::emit_dimensions(std::ostream&out) const } dims.push_back(cur); + bool name_emitted = false; + while (! dims.empty()) { cur = dims.front(); dims.pop_front(); - out << "["; - if (cur->dimension(0).msb() && cur->dimension(0).lsb()) { - // bounded array, unbounded arrays have msb() & lsb() nullified - errors += cur->dimension(0).msb()->emit(out, 0, 0); - out << ":"; - errors += cur->dimension(0).lsb()->emit(out, 0, 0); + if(!packed) { + emit_name(out, name); + name_emitted = true; } - out << "]"; + + for(unsigned i = 0; i < cur->dimensions(); ++i) { + if(cur->dimension(i).is_box() && !name_emitted) { + emit_name(out, name); + name_emitted = true; + } + + out << "["; + if (!cur->dimension(i).is_box()) { // if not unbounded { + errors += cur->dimension(i).msb()->emit(out, 0, 0); + out << ":"; + errors += cur->dimension(i).lsb()->emit(out, 0, 0); + } + out << "]"; + } + } + + if(!name_emitted) { + emit_name(out, name); } return errors; @@ -200,10 +209,11 @@ int VTypeRecord::emit_def(ostream&out, perm_string name) const * type. (We are defining a variable here, not the type itself.) The * emit_typedef() method was presumably called to define type already. */ -int VTypeDef::emit_def(ostream&out, perm_string) const +int VTypeDef::emit_def(ostream&out, perm_string name) const { int errors = 0; emit_name(out, name_); + emit_name(out, name); return errors; } diff --git a/vpi/sys_darray.c b/vpi/sys_darray.c index e6d76d3bd..507bb974a 100644 --- a/vpi/sys_darray.c +++ b/vpi/sys_darray.c @@ -143,6 +143,7 @@ static PLI_INT32 to_from_vec_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) case vpiReg: case vpiBitVar: case vpiIntegerVar: + case vpiConstant: break; default: vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),