diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index b27deeff3..256970085 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -757,6 +757,8 @@ int ExpFunc::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) ivl_assert(*this, def_==0); def_ = prog; + bool new_instance = false; + // Elaborate arguments for (size_t idx = 0 ; idx < argv_.size() ; idx += 1) { const VType*tmp = argv_[idx]->probe_type(ent, scope); @@ -769,10 +771,15 @@ int ExpFunc::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) // Type casting for unbounded arrays if(param_type && param_type->is_unbounded() /*&& !param_type->type_match(tmp)*/) { - argv_[idx] = new ExpCast(argv_[idx], get_global_typedef(param_type)); + new_instance = true; // we need a new instance } } + if(new_instance) { + def_ = prog->make_instance(argv_, scope); + name_ = def_->name(); + } + return errors; } diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index 8fd94b73e..6bb7ed4e5 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -62,6 +62,13 @@ class ScopeBase { // 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/subprogram.cc b/vhdlpp/subprogram.cc index a6bd8f63f..56d07a599 100644 --- a/vhdlpp/subprogram.cc +++ b/vhdlpp/subprogram.cc @@ -50,7 +50,6 @@ void Subprogram::set_program_body(list*stmt) { ivl_assert(*this, statements_==0); statements_ = stmt; - fix_variables(); fix_port_types(); } @@ -73,12 +72,6 @@ private: void Subprogram::fix_port_types() { // Check function parameters for unbounded vectors and possibly fix it. - if(ports_) { - for(std::list::iterator it = ports_->begin(); - it != ports_->end(); ++it) { - check_unb_vector((*it)->type); - } - } // Try to settle at a fixed width return type. if(fixed_return_type()) @@ -104,37 +97,16 @@ void Subprogram::fix_variables() { Variable*var = it->second; const VType*type = var->peek_type(); - // SystemVerilog does not handle variables that have length dependendent - // on other variables. We have to convert it to a dynamic array and - // construct it. if(type->is_variable_length(this)) { const VTypeArray*arr = dynamic_cast(type); // Currently we handle only one dimensional variables assert(arr->dimensions() == 1); - Expression*lsb = arr->dimension(0).lsb(); - Expression*msb = arr->dimension(0).msb(); - - // We cannot have dynamic arrays with custom range, - // it has to be [size-1:0] - int64_t lsb_val; - assert(lsb->evaluate(NULL, lsb_val) && lsb_val == 0); - //ExpArithmetic*size = new ExpArithmetic(ExpArithmetic::MINUS, msb, lsb); - // Because lsb_val == 0, we may simplify the size expression: - Expression*size = msb; - - // Prepare the construction statement - assert(statements_); - VariableSeqAssignment*init = new VariableSeqAssignment(new ExpName(var->peek_name()), - new ExpNew(size)); - statements_->push_front(init); - // Now substitute the variable type - std::vector new_range; - new_range.push_back(VTypeArray::range_t()); - VTypeArray*new_array = new VTypeArray(arr->element_type(), new_range); - it->second = new Variable(var->peek_name(), fix_logic_darray(new_array)); + VTypeArray*new_array = static_cast(arr->clone()); + new_array->evaluate_ranges(this); + it->second = new Variable(var->peek_name(), new_array); delete var; } } @@ -216,6 +188,41 @@ const VType*Subprogram::peek_param_type(int idx) const return (*p)->type; } +Subprogram*Subprogram::make_instance(std::vector arguments, ScopeBase*scope) { + assert(arguments.size() == ports_->size()); + + std::list*ports = new std::list; + int i = 0; + + // 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_); + 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) {} diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h index 2eab8f59c..bba9c757f 100644 --- a/vhdlpp/subprogram.h +++ b/vhdlpp/subprogram.h @@ -45,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. @@ -62,6 +63,12 @@ class Subprogram : public LineInfo, public ScopeBase { void write_to_stream(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); + private: // Tries to set the return type to a fixed type. VHDL functions that // return std_logic_vectors do not specify its length, as SystemVerilog