vhdlpp: Subprograms can have instances that take a different set of parameter types.
This commit is contained in:
parent
8a854affa6
commit
1a367c84b6
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue