vhdlpp: Subprograms can have instances that take a different set of parameter types.

This commit is contained in:
Maciej Suminski 2015-02-02 11:50:50 +01:00
parent 8a854affa6
commit 1a367c84b6
4 changed files with 60 additions and 32 deletions

View File

@ -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;
}

View File

@ -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<perm_string, Subprogram*>::iterator it;
if((it = use_subprograms_.find(name)) != use_subprograms_.end() )
use_subprograms_.erase(it);
cur_subprograms_[name] = obj;
}
protected:
void cleanup();

View File

@ -50,7 +50,6 @@ void Subprogram::set_program_body(list<SequentialStmt*>*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<InterfacePort*>::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<const VTypeArray*>(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<VTypeArray::range_t> 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<VTypeArray*>(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<Expression*> arguments, ScopeBase*scope) {
assert(arguments.size() == ports_->size());
std::list<InterfacePort*>*ports = new std::list<InterfacePort*>;
int i = 0;
// Change the argument types to match the ones that were used during
// the function call
for(std::list<InterfacePort*>::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<perm_string,Variable*>::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) {}

View File

@ -45,6 +45,7 @@ class Subprogram : public LineInfo, public ScopeBase {
inline const perm_string&name() const { return name_; }
void set_program_body(std::list<SequentialStmt*>*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<Expression*> 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