Merge pull request #45 from orsonmmz/subprogram

Subprograms
This commit is contained in:
Stephen Williams 2014-10-02 14:14:52 -07:00
commit 2397aa1587
18 changed files with 187 additions and 24 deletions

View File

@ -21,6 +21,7 @@
# include "entity.h"
# include "expression.h"
# include "sequential.h"
# include "subprogram.h"
# include "vsignal.h"
# include <iostream>
# include <typeinfo>

View File

@ -34,8 +34,4 @@ extern StringHeapLex lex_strings;
extern StringHeapLex filename_strings;
extern void library_set_work_path(const char*work_path);
extern void library_add_directory(const char*directory);
extern int emit_packages(void);
#endif /* IVL_compiler_H */

View File

@ -23,6 +23,7 @@
# include "architec.h"
# include "expression.h"
# include "parse_types.h"
# include "subprogram.h"
# include "sequential.h"
# include "vsignal.h"
# include "vtype.h"

View File

@ -23,6 +23,8 @@
# include "architec.h"
# include "entity.h"
# include "vsignal.h"
# include "subprogram.h"
# include "library.h"
# include <iostream>
# include <typeinfo>
# include "parse_types.h"
@ -710,11 +712,16 @@ int ExpFunc::elaborate_expr(Entity*ent, Architecture*arc, const VType*)
ivl_assert(*this, arc);
Subprogram*prog = arc->find_subprogram(name_);
if(!prog)
prog = library_find_subprogram(name_);
ivl_assert(*this, def_==0);
def_ = prog;
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);
}

View File

@ -22,6 +22,7 @@
# include "vtype.h"
# include "architec.h"
# include "package.h"
# include "subprogram.h"
# include "parse_types.h"
# include <typeinfo>
# include <iostream>

View File

@ -69,7 +69,25 @@ void library_add_directory(const char*directory)
return;
}
library_search_path .push_front(directory);
library_search_path.push_front(directory);
}
Subprogram*library_find_subprogram(perm_string name)
{
Subprogram*subp = NULL;
map<perm_string,struct library_contents>::const_iterator lib_it;
for(lib_it = libraries.begin(); lib_it != libraries.end(); ++lib_it) {
const struct library_contents&lib = lib_it->second;
map<perm_string,Package*>::const_iterator pack_it;
for(pack_it = lib.packages.begin(); pack_it != lib.packages.end(); ++pack_it) {
if((subp = pack_it->second->find_subprogram(name)))
return subp;
}
}
return NULL;
}
static void store_package_in_work(const Package*pack);

32
vhdlpp/library.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef IVL_library_H
#define IVL_library_H
/*
* Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
class Subprogram;
extern void library_set_work_path(const char*work_path);
extern void library_add_directory(const char*directory);
extern Subprogram*library_find_subprogram(perm_string name);
extern int emit_packages(void);
#endif /* IVL_library_H */

View File

@ -75,6 +75,7 @@ const char NOTICE[] =
;
# include "compiler.h"
# include "library.h"
# include "parse_api.h"
# include "vtype.h"
# include <fstream>

View File

@ -20,6 +20,7 @@
# include "package.h"
# include "entity.h"
# include "subprogram.h"
# include "parse_misc.h"
# include "ivl_assert.h"

View File

@ -19,6 +19,7 @@
*/
# include "package.h"
# include "subprogram.h"
# include <iostream>
# include "ivl_assert.h"

View File

@ -83,6 +83,7 @@ extern int yylex(union YYSTYPE*yylvalp,YYLTYPE*yyllocp,yyscan_t yyscanner);
*/
static ActiveScope*active_scope = new ActiveScope;
static stack<ActiveScope*> scope_stack;
static Subprogram*active_sub = NULL;
/*
* When a scope boundary starts, call the push_scope function to push
@ -106,6 +107,13 @@ static void pop_scope(void)
scope_stack.pop();
}
static bool is_subprogram_param(perm_string name)
{
if(!active_sub)
return false;
return (active_sub->find_param(name) != NULL);
}
void preload_global_types(void)
{
@ -1543,7 +1551,7 @@ name /* IEEE 1076-2008 P8.1 */
| IDENTIFIER '(' expression_list ')'
{ perm_string name = lex_strings.make($1);
delete[]$1;
if (active_scope->is_vector_name(name)) {
if (active_scope->is_vector_name(name) || is_subprogram_param(name)) {
ExpName*tmp = new ExpName(name, $3);
$$ = tmp;
} else {
@ -1813,16 +1821,7 @@ procedure_call_statement
;
process_declarative_item
: K_variable identifier_list ':' subtype_indication ';'
{ /* Save the signal declaration in the block_signals map. */
for (std::list<perm_string>::iterator cur = $2->begin()
; cur != $2->end() ; ++cur) {
Variable*sig = new Variable(*cur, $4);
FILE_NAME(sig, @1);
active_scope->bind_name(*cur, sig);
}
delete $2;
}
: variable_declaration
;
process_declarative_part
@ -2175,6 +2174,7 @@ signal_assignment_statement
subprogram_body /* IEEE 1076-2008 P4.3 */
: subprogram_specification K_is
{ active_sub = $1; }
subprogram_declarative_part
K_begin subprogram_statement_part K_end
subprogram_kind_opt identifier_opt ';'
@ -2186,8 +2186,10 @@ subprogram_body /* IEEE 1076-2008 P4.3 */
} else if (tmp) {
errormsg(@1, "Subprogram specification for %s doesn't match specification in package header.\n", prog->name().str());
}
prog->set_program_body($5);
prog->transfer_from(*active_scope);
prog->set_program_body($6);
active_scope->bind_name(prog->name(), prog);
active_sub = NULL;
}
| subprogram_specification K_is
@ -2410,8 +2412,15 @@ variable_assignment_statement /* IEEE 1076-2008 P10.6.1 */
variable_declaration /* IEEE 1076-2008 P6.4.2.4 */
: K_shared_opt K_variable identifier_list ':' subtype_indication ';'
{ sorrymsg(@2, "variable_declaration not supported.\n"); }
{ /* Save the signal declaration in the block_signals map. */
for (std::list<perm_string>::iterator cur = $3->begin()
; cur != $3->end() ; ++cur) {
Variable*sig = new Variable(*cur, $5);
FILE_NAME(sig, @2);
active_scope->bind_name(*cur, sig);
}
delete $3;
}
| K_shared_opt K_variable error ';'
{ errormsg(@2, "Syntax error in variable declaration.\n");
yyerrok;

View File

@ -20,6 +20,7 @@
# include "scope.h"
# include "package.h"
# include "subprogram.h"
# include <algorithm>
# include <iostream>
# include <iterator>
@ -202,6 +203,27 @@ void ScopeBase::do_use_from(const ScopeBase*that)
}
}
void ScopeBase::transfer_from(ScopeBase&ref)
{
std::copy(ref.new_signals_.begin(), ref.new_signals_.end(),
insert_iterator<map<perm_string, Signal*> >(
new_signals_, new_signals_.end())
);
ref.new_signals_.clear();
std::copy(ref.new_variables_.begin(), ref.new_variables_.end(),
insert_iterator<map<perm_string, Variable*> >(
new_variables_, new_variables_.end())
);
ref.new_variables_.clear();
std::copy(ref.new_components_.begin(), ref.new_components_.end(),
insert_iterator<map<perm_string, ComponentBase*> >(
new_components_, new_components_.end())
);
ref.new_components_.clear();
}
void ActiveScope::set_package_header(Package*pkg)
{
assert(package_header_ == 0);

View File

@ -26,7 +26,6 @@
# include "StringHeap.h"
# include "entity.h"
# include "expression.h"
# include "subprogram.h"
# include "vsignal.h"
class ActiveScope;
@ -58,6 +57,9 @@ class ScopeBase {
Signal* find_signal(perm_string by_name) const;
Variable* find_variable(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);
protected:
void cleanup();
@ -203,7 +205,7 @@ class ActiveScope : public ScopeBase {
{ map<perm_string, Subprogram*>::iterator it;
if((it = use_subprograms_.find(name)) != use_subprograms_.end() )
use_subprograms_.erase(it);
cur_subprograms_[name] = obj;;
cur_subprograms_[name] = obj;
}
void bind(Entity*ent)

View File

@ -120,6 +120,8 @@ class ReturnStmt : public SequentialStmt {
int emit(ostream&out, Entity*entity, Architecture*arc);
void dump(ostream&out, int indent) const;
const Expression*peek_expr() const { return val_; };
private:
Expression*val_;
};

View File

@ -21,6 +21,7 @@
# include "subprogram.h"
# include "entity.h"
# include "vtype.h"
# include "sequential.h"
# include "ivl_assert.h"
using namespace std;
@ -45,6 +46,7 @@ void Subprogram::set_program_body(list<SequentialStmt*>*stmt)
{
ivl_assert(*this, statements_==0);
statements_ = stmt;
fix_return_type();
}
bool Subprogram::compare_specification(Subprogram*that) const
@ -78,6 +80,57 @@ bool Subprogram::compare_specification(Subprogram*that) const
return true;
}
const InterfacePort*Subprogram::find_param(perm_string nam) const
{
if(!ports_)
return NULL;
for (std::list<InterfacePort*>::const_iterator it = ports_->begin()
; it != ports_->end(); ++it) {
if((*it)->name == nam)
return *it;
}
return NULL;
}
const VType*Subprogram::peek_param_type(int idx) const
{
if(!ports_ || idx >= ports_->size())
return NULL;
std::list<InterfacePort*>::const_iterator p = ports_->begin();
std::advance(p, idx);
return (*p)->type;
}
void Subprogram::fix_return_type(void)
{
if(!statements_)
return;
const ReturnStmt*ret = NULL;
const VType*t = NULL;
for (std::list<SequentialStmt*>::const_iterator s = statements_->begin()
; s != statements_->end(); ++s) {
if((ret = dynamic_cast<const ReturnStmt*>(*s))) {
const Expression*expr = ret->peek_expr();
if(const ExpName*n = dynamic_cast<const ExpName*>(expr)) {
if(Variable*v = find_variable(n->peek_name()))
t = v->peek_type();
} else {
t = expr->peek_type();
}
if(t)
return_type_ = t;
}
}
}
void Subprogram::write_to_stream(ostream&fd) const
{
fd << " function " << name_ << "(";

View File

@ -22,15 +22,15 @@
# include "StringHeap.h"
# include "LineInfo.h"
# include "scope.h"
# include <iostream>
# include <list>
class InterfacePort;
class ScopeBase;
class SequentialStmt;
class VType;
class Subprogram : public LineInfo {
class Subprogram : public LineInfo, public ScopeBase {
public:
Subprogram(perm_string name, std::list<InterfacePort*>*ports,
@ -48,6 +48,11 @@ class Subprogram : public LineInfo {
// matches this subprogram and that subprogram.
bool compare_specification(Subprogram*that) const;
const InterfacePort*find_param(perm_string nam) const;
const VType*peek_param_type(int idx) const;
int emit(ostream&out, Entity*ent, Architecture*arc);
// Emit a definition as it would show up in a package.
int emit_package(std::ostream&fd) const;
@ -55,6 +60,10 @@ class Subprogram : public LineInfo {
void dump(std::ostream&fd) 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);
perm_string name_;
const ScopeBase*parent_;
std::list<InterfacePort*>*ports_;

View File

@ -60,6 +60,13 @@ int Subprogram::emit_package(ostream&fd) const
fd << ");" << endl;
for (map<perm_string,Variable*>::const_iterator cur = new_variables_.begin()
; cur != new_variables_.end() ; ++cur) {
// Workaround to enable reg_flag for variables
cur->second->count_ref_sequ();
errors += cur->second->emit(fd, NULL, NULL);
}
if (statements_) {
for (list<SequentialStmt*>::const_iterator cur = statements_->begin()
; cur != statements_->end() ; ++cur) {

View File

@ -86,7 +86,7 @@ class VType {
virtual bool can_be_packed() const { return false; }
private:
friend class decl_t;
friend struct decl_t;
// This virtual method is called to emit the declaration. This
// is used by the decl_t object to emit variable/wire/port declarations.
virtual int emit_decl(std::ostream&out, perm_string name, bool reg_flag) const;