diff --git a/elab_expr.cc b/elab_expr.cc index b9f3c3b71..962bbc859 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1078,7 +1078,7 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope, if (name=="$ivlh_to_unsigned") { ivl_assert(*this, parms_.size() == 2); - // The Icarus Verilog specific $ivl_unsigned() system + // The Icarus Verilog specific $ivlh_to_unsigned() system // task takes a second argument which is the output // size. This can be an arbitrary constant function. PExpr*pexpr = parms_[1]; @@ -1100,6 +1100,8 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope, bool rc = eval_as_long(value, nexpr); ivl_assert(*this, rc && value>=0); + parms_[0]->test_width(des, scope, mode); + expr_width_ = value; signed_flag_= false; return expr_width_; diff --git a/expr_synth.cc b/expr_synth.cc index db0f035b1..b1a2a8165 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -1138,18 +1138,29 @@ NetNet* NetESelect::synthesize(Design *des, NetScope*scope, NetExpr*root) if (sub->vector_width() == expr_width()) return sub; - // The vector_width is not exactly right, so the source is - // probably asking for padding. Create nodes to do sign - // extension or 0 extension, depending on the has_sign() mode - // of the expression. - netvector_t*net_vec = new netvector_t(expr_type(), expr_width()-1, 0); net_vec->set_signed(has_sign()); NetNet*net = new NetNet(scope, scope->local_symbol(), NetNet::IMPLICIT, net_vec); net->set_line(*this); net->local_flag(true); - if (has_sign()) { + + // It may still happen that the expression is wider than the selection, + // and there was no part select created earlier (size casting). + if(expr_width() < sub->vector_width()) { + NetPartSelect*sel = new NetPartSelect(sub, 0, expr_width(), + NetPartSelect::VP, has_sign()); + sel->set_line(*this); + des->add_node(sel); + + connect(net->pin(0), sel->pin(0)); + + // The vector_width is not exactly right, so the source is + // probably asking for padding. Create nodes to do sign + // extension or 0 extension, depending on the has_sign() mode + // of the expression. + + } else if (has_sign()) { NetSignExtend*pad = new NetSignExtend(scope, scope->local_symbol(), expr_width()); @@ -1166,7 +1177,6 @@ NetNet* NetESelect::synthesize(Design *des, NetScope*scope, NetExpr*root) cat->set_line(*this); des->add_node(cat); - assert(expr_width() > sub->vector_width()); unsigned pad_width = expr_width() - sub->vector_width(); verinum pad((uint64_t)0, pad_width); NetConst*con = new NetConst(scope, scope->local_symbol(), diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index 9a389d2ae..7c2295718 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -1,6 +1,7 @@ /* * Copyright (c) 2011 Stephen Williams (steve@icarus.com) - * Copyright (c) 2014 CERN / Maciej Suminski (maciej.suminski@cern.ch) + * Copyright (c) 2014 CERN + * @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 diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index 04775f13d..77d80a4d6 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -1,7 +1,7 @@ /* * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) * Copyright CERN 2012-2015 / Stephen Williams (steve@icarus.com), - * Maciej Suminski (maciej.suminski@cern.ch) + * @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 diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index dd1ae6783..7d5f47ee6 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -3,7 +3,7 @@ /* * Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2015 / Stephen Williams (steve@icarus.com), - * Maciej Suminski (maciej.suminski@cern.ch) + * @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 @@ -516,12 +516,14 @@ class ExpFunc : public Expression { Expression*clone() const; + const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) 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 + 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); diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index e4389caca..30ddd4e2f 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -80,11 +80,7 @@ const VType*ExpName::elaborate_adjust_type_with_range_(Entity*, ScopeBase*scope, flag = lsb_->evaluate(scope, use_lsb); ivl_assert(*this, flag); - Expression*exp_msb = new ExpInteger(use_msb); - Expression*exp_lsb = new ExpInteger(use_lsb); - vector use_dims (1); - use_dims[0] = VTypeArray::range_t(exp_msb, exp_lsb); - type = new VTypeArray(array->element_type(), use_dims); + type = new VTypeArray(array->element_type(), use_msb, use_lsb); } } @@ -600,9 +596,7 @@ const VType*ExpBitstring::fit_type(Entity*, ScopeBase*, const VTypeArray*atype) 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); + const VTypeArray*type = new VTypeArray(&primitive_STDLOGIC, value_.size() - 1, 0); set_type(type); return errors; } @@ -750,6 +744,56 @@ int ExpConditional::else_t::elaborate_expr(Entity*ent, ScopeBase*scope, const VT return errors; } +const VType*ExpFunc::probe_type(Entity*ent, ScopeBase*scope) const +{ + if(name_ == "integer") + return &primitive_INTEGER; + + if(name_ == "unsigned" || name_ == "resize") { + if(argv_.empty()) + return NULL; + + const VType*type = argv_[0]->probe_type(ent, scope); + if(!type) + return NULL; + + int msb = type->get_width(scope) - 1; + ivl_assert(*this, msb >= 0); + + // Determine the sign + bool sign = false; + if(name_ == "resize") { + if(const VTypeArray*arr = dynamic_cast(type)) + sign = arr->signed_vector(); + } + + return new VTypeArray(&primitive_BIT, msb, 0, sign); + } + + if(name_ == "std_logic_vector" || name_ == "conv_std_logic_vector") { + if(argv_.empty()) + return NULL; + + const VType*type = argv_[0]->probe_type(ent, scope); + if(!type) + return NULL; + + int msb = type->get_width(scope) - 1; + + return new VTypeArray(&primitive_STDLOGIC, msb, 0); + } + + Subprogram*prog = scope->find_subprogram(name_); + + if(!prog) + prog = library_find_subprogram(name_); + + if(!prog) + return NULL; + + return prog->peek_return_type(); +} + int ExpFunc::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) { int errors = 0; @@ -782,6 +826,73 @@ int ExpFunc::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) return errors; } +const VType* ExpFunc::fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*) const +{ + // Built-in functions + if(name_ == "to_integer" || name_ == "unsigned" || name_ == "integer") { + ivl_assert(*this, argv_.size() == 1); + + const VType*type = argv_[0]->probe_type(ent, scope); + ivl_assert(*this, type); + + // Determine the sign + bool sign = false; + + if(name_ == "integer") { + sign = true; + } else if(name_ == "to_integer") { + if(const VTypeArray*arr = dynamic_cast(type)) + sign = arr->signed_vector(); + } + + return new VTypeArray(&primitive_BIT, type->get_width(scope), 0, sign); + } + + if(name_ == "to_unsigned" || name_ == "std_logic_vector" || + name_ == "conv_std_logic_vector" || name_ == "resize") + { + ivl_assert(*this, argv_.size() == 2); + + // Determine the sign + bool sign = false; + const VType*element = &primitive_STDLOGIC; + + if(name_ == "resize") { + const VType*type = argv_[0]->probe_type(ent, scope); + ivl_assert(*this, type); + + if(const VTypeArray*arr = dynamic_cast(type)) + { + sign = arr->signed_vector(); + element = arr->element_type(); + } + } else if(name_ == "to_unsigned") { + element = &primitive_BIT; + } + + int64_t width = 0; + bool evaluated = argv_[1]->evaluate(scope, width); + ivl_assert(*this, evaluated); + + return new VTypeArray(element, width, 0, sign); + } + + // Other cases + Subprogram*prog = def_; + + if(!prog) { + ivl_assert(*this, scope); + prog = scope->find_subprogram(name_); + } + + if(!prog) + prog = library_find_subprogram(name_); + + ivl_assert(*this, prog); + + return def_->peek_return_type(); +} + const VType* ExpInteger::probe_type(Entity*, ScopeBase*) const { return &primitive_INTEGER; @@ -871,6 +982,13 @@ const VType* ExpName::probe_prefixed_type_(Entity*ent, ScopeBase*scope) const return element_type; } + if (const VTypeArray*pref_array = dynamic_cast (prefix_type)) { + const VType*element_type = pref_array->element_type(); + ivl_assert(*this, element_type); + + return element_type; + } + cerr << get_fileline() << ": sorry: I don't know how to probe " << "prefix type " << typeid(*prefix_type).name() << " of " << name_ << "." << endl; @@ -991,13 +1109,8 @@ const VType*ExpString::fit_type(Entity*, ScopeBase*, const VTypeArray*atype) con // Generate an array range for this string ivl_assert(*this, range.size() == 1); - ExpInteger*use_msb = new ExpInteger(value_.size()); - ExpInteger*use_lsb = new ExpInteger(0); - FILE_NAME(use_msb, this); - FILE_NAME(use_lsb, this); - range[0] = VTypeArray::range_t(use_msb, use_lsb); - VTypeArray*type = new VTypeArray(atype->element_type(), range); + VTypeArray*type = new VTypeArray(atype->element_type(), value_.size(), 0); return type; } diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 1d8af85b2..39e853a71 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -1,7 +1,7 @@ /* * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) * Copyright CERN 2012-2015 / Stephen Williams (steve@icarus.com) - * Maciej Suminski (maciej.suminski@cern.ch) + * @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 @@ -560,13 +560,7 @@ int ExpFunc::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; - // SystemVerilog takes care of sign & width, depending on the lvalue type - if ((name_ == "to_integer" && argv_.size() == 1) || - (name_ == "resize" && argv_.size() == 2)) { - errors += argv_[0]->emit(out, ent, scope); - } - - else if (name_ == "unsigned" && argv_.size() == 1) { + if (name_ == "unsigned" && argv_.size() == 1) { // Handle the special case that this is a cast to // unsigned. This function is brought in as part of the // std numeric library, but we interpret it as the same @@ -580,6 +574,25 @@ int ExpFunc::emit(ostream&out, Entity*ent, ScopeBase*scope) errors += argv_[0]->emit(out, ent, scope); out << ")"; + } else if (name_ == "to_integer" && argv_.size() == 1) { + bool signed_flag = false; + + // to_integer converts unsigned to natural + // signed to integer + // try to determine the converted type + const VType*type = argv_[0]->probe_type(ent, scope); + const VTypeArray*array = dynamic_cast(type); + + if(array) + signed_flag = array->signed_vector(); + else + cerr << get_fileline() << ": sorry: Could not determine the " + << "expression sign. Output may be erroneous." << endl; + + out << (signed_flag ? "$signed(" : "$unsigned("); + 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 @@ -596,7 +609,8 @@ int ExpFunc::emit(ostream&out, Entity*ent, ScopeBase*scope) errors += argv_[1]->emit(out, ent, scope); out << ")"; - } else if (name_ == "conv_std_logic_vector" && argv_.size() == 2) { + } else if ((name_ == "conv_std_logic_vector" || name_ == "resize") && + argv_.size() == 2) { int64_t use_size; bool rc = argv_[1]->evaluate(ent, scope, use_size); ivl_assert(*this, rc); @@ -604,12 +618,12 @@ int ExpFunc::emit(ostream&out, Entity*ent, ScopeBase*scope) errors += argv_[0]->emit(out, ent, scope); out << ")"; - } else if (name_ == "rising_edge" && argv_.size()==1) { + } else if (name_ == "rising_edge" && argv_.size() == 1) { out << "$ivlh_rising_edge("; errors += argv_[0]->emit(out, ent, scope); out << ")"; - } else if (name_ == "falling_edge" && argv_.size()==1) { + } else if (name_ == "falling_edge" && argv_.size() == 1) { out << "$ivlh_falling_edge("; errors += argv_[0]->emit(out, ent, scope); out << ")"; diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 48235e0a1..3276dc6d9 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -8,7 +8,7 @@ /* * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) * Copyright CERN 2012-2014 / Stephen Williams (steve@icarus.com), - * Maciej Suminski (maciej.suminski@cern.ch) + * @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 diff --git a/vhdlpp/vsignal.cc b/vhdlpp/vsignal.cc index 94bd8959b..043c2b1a9 100644 --- a/vhdlpp/vsignal.cc +++ b/vhdlpp/vsignal.cc @@ -1,6 +1,7 @@ /* * Copyright (c) 2011 Stephen Williams (steve@icarus.com) - * Copyright CERN 2014 / Maciej Suminski (maciej.suminski@cern.ch) + * Copyright CERN 2014 + * @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 diff --git a/vhdlpp/vtype.cc b/vhdlpp/vtype.cc index 7a6581148..17001977f 100644 --- a/vhdlpp/vtype.cc +++ b/vhdlpp/vtype.cc @@ -93,6 +93,11 @@ int VTypePrimitive::get_width(ScopeBase*) const case CHARACTER: return 8; + + default: + std::cerr << "sorry: primitive type " << type_ << + " has no get_width() implementation." << std::endl; + break; } return -1; @@ -128,6 +133,12 @@ VTypeArray::VTypeArray(const VType*element, std::list*r, bool sv) } } +VTypeArray::VTypeArray(const VType*element, int msb, int lsb, bool sv) +: etype_(element), ranges_(1), signed_flag_(sv), parent_(NULL) +{ + bool down_to = msb > lsb; + ranges_[0] = range_t(new ExpInteger(msb), new ExpInteger(lsb), down_to); +} VTypeArray::~VTypeArray() { diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index 47683b637..5b00bc885 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -3,7 +3,7 @@ /* * Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2014 / Stephen Williams (steve@icarus.com), - * Maciej Suminski (maciej.suminski@cern.ch) + * @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 @@ -199,8 +199,8 @@ class VTypeArray : public VType { public: class range_t { public: - range_t(Expression*m = NULL, Expression*l = NULL, bool dir = true) : - msb_(m), lsb_(l), direction_(dir) { } + range_t(Expression*m = NULL, Expression*l = NULL, bool down_to = true) : + msb_(m), lsb_(l), direction_(down_to) { } range_t*clone() const; @@ -217,8 +217,9 @@ class VTypeArray : public VType { }; public: - VTypeArray(const VType*etype, const std::vector&r, bool signed_vector =false); - VTypeArray(const VType*etype, std::list*r, bool signed_vector =false); + VTypeArray(const VType*etype, const std::vector&r, bool signed_vector = false); + VTypeArray(const VType*etype, std::list*r, bool signed_vector = false); + VTypeArray(const VType*etype, int msb, int lsb, bool signed_vector = false); ~VTypeArray(); VType*clone() const; diff --git a/vhdlpp/vtype_emit.cc b/vhdlpp/vtype_emit.cc index e64e18aa5..64577e004 100644 --- a/vhdlpp/vtype_emit.cc +++ b/vhdlpp/vtype_emit.cc @@ -1,6 +1,7 @@ /* * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) - * Copyright (c) 2014 CERN / Maciej Suminski (maciej.suminski@cern.ch) + * Copyright (c) 2014 CERN + * @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