vhdlpp: Refactored the way of handling standard VHDL library functions.

This commit is contained in:
Maciej Suminski 2015-06-10 18:41:51 +02:00
parent 356a09d295
commit 169228ad0f
15 changed files with 399 additions and 243 deletions

View File

@ -57,7 +57,7 @@ LIBS = @LIBS@ @EXTRALIBS@
M = StringHeap.o LineInfo.o
O = main.o architec.o compiler.o entity.o \
O = main.o architec.o compiler.o entity.o std_funcs.o \
expression.o package.o scope.o sequential.o subprogram.o vsignal.o vtype.o \
vtype_match.o \
architec_elaborate.o entity_elaborate.o expression_elaborate.o \

View File

@ -34,7 +34,16 @@ class Expression;
class InterfacePort : public LineInfo {
public:
InterfacePort() { mode = PORT_NONE; type=0; expr=0; }
InterfacePort(port_mode_t mod = PORT_NONE,
perm_string nam = empty_perm_string,
const VType*typ = NULL,
Expression*exp = NULL)
: mode(mod), name(nam), type(typ), expr(exp)
{}
InterfacePort(const VType*typ)
: mode(PORT_NONE), type(typ), expr(NULL)
{}
// Port direction from the source code.
port_mode_t mode;

View File

@ -738,53 +738,22 @@ int ExpConditional::case_t::elaborate_expr(Entity*ent, ScopeBase*scope, const VT
return errors;
}
const VType*ExpFunc::probe_type(Entity*ent, ScopeBase*scope) const
const VType*ExpFunc::probe_type(Entity*, ScopeBase*scope) const
{
if(name_ == "integer")
return &primitive_INTEGER;
SubprogramHeader*prog = def_;
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<const VTypeArray*>(type))
sign = arr->signed_vector();
}
return new VTypeArray(&primitive_BIT, msb, 0, sign);
if(!prog) {
prog = scope->find_subprogram(name_);
}
if(name_ == "std_logic_vector" || name_ == "conv_std_logic_vector") {
if(argv_.empty())
return NULL;
if(!prog)
prog = library_find_subprogram(name_);
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);
if(!prog) {
cerr << get_fileline() << ": sorry: VHDL function " << name_ << " not yet implemented" << endl;
ivl_assert(*this, false);
}
SubprogramHeader*prog = scope->find_subprogram(name_);
if(!prog)
prog = library_find_subprogram(name_);
if(!prog)
return NULL;
return prog->peek_return_type();
}
@ -812,86 +781,25 @@ int ExpFunc::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*)
errors += argv_[idx]->elaborate_expr(ent, scope, tmp);
}
if(def_ && def_->unbounded()) {
// SystemVerilog functions work only with defined size data types, therefore
// if header does not specify argument or return type size, create a function
// instance that work with this particular size.
if(def_ && !def_->is_std() && def_->unbounded()) {
def_ = prog->make_instance(argv_, scope);
name_ = def_->name();
}
if(!def_) {
cerr << get_fileline() << ": error: could not find function " << name_ << endl;
++errors;
}
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<const VTypeArray*>(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<const VTypeArray*>(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);
}
if(name_ == "and_reduce" || name_ == "or_reduce") {
ivl_assert(*this, argv_.size() == 1);
const VType*element = &primitive_STDLOGIC;
return new VTypeArray(element, 0, 0, false);
}
// Other cases
SubprogramHeader*prog = def_;
if(!prog) {
ivl_assert(*this, scope);
prog = scope->find_subprogram(name_);
}
if(!prog)
prog = library_find_subprogram(name_);
cerr << get_fileline() << ": sorry: VHDL function " << name_ << " not yet implemented" << endl;
ivl_assert(*this, prog);
return def_->peek_return_type();
return probe_type(ent, scope);
}
const VType* ExpInteger::probe_type(Entity*, ScopeBase*) const

View File

@ -23,7 +23,7 @@
# include "vtype.h"
# include "architec.h"
# include "package.h"
# include "subprogram.h"
# include "std_funcs.h"
# include "parse_types.h"
# include <typeinfo>
# include <iostream>
@ -567,103 +567,21 @@ int ExpFunc::emit(ostream&out, Entity*ent, ScopeBase*scope)
{
int errors = 0;
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
// as the $unsigned function.
out << "$unsigned(";
errors += argv_[0]->emit(out, ent, scope);
out << ")";
ivl_assert(*this, def_);
} else if (name_ == "integer" && argv_.size() == 1) {
out << "$signed(";
errors += argv_[0]->emit(out, ent, scope);
out << ")";
// If this function has an elaborated definition, and if
// that definition is in a package, then include the
// package name as a scope qualifier. This assures that
// the SV elaborator finds the correct VHDL elaborated
// definition.
const Package*pkg = dynamic_cast<const Package*> (def_->get_parent());
if (pkg != 0)
out << "\\" << pkg->name() << " ::";
} 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<const VTypeArray*>(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
// have to do anything for that to work.
out << "(";
errors += argv_[0]->emit(out, ent, scope);
out << ")";
} else if (name_ == "to_unsigned" && argv_.size() == 2) {
out << "$ivlh_to_unsigned(";
errors += argv_[0]->emit(out, ent, scope);
out << ", ";
errors += argv_[1]->emit(out, ent, scope);
out << ")";
} 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);
out << use_size << "'(";
errors += argv_[0]->emit(out, ent, scope);
out << ")";
} 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) {
out << "$ivlh_falling_edge(";
errors += argv_[0]->emit(out, ent, scope);
out << ")";
} else if (name_ == "and_reduce" && argv_.size() == 1) {
out << "&(";
errors += argv_[0]->emit(out, ent, scope);
out << ")";
} else if (name_ == "or_reduce" && argv_.size() == 1) {
out << "|(";
errors += argv_[0]->emit(out, ent, scope);
out << ")";
} else {
// If this function has an elaborated definition, and if
// that definition is in a package, then include the
// package name as a scope qualifier. This assures that
// the SV elaborator finds the correct VHDL elaborated
// definition.
if (def_) {
const Package*pkg = dynamic_cast<const Package*> (def_->get_parent());
if (pkg != 0)
out << "\\" << pkg->name() << " ::";
}
out << "\\" << name_ << " (";
for (size_t idx = 0; idx < argv_.size() ; idx += 1) {
if (idx > 0) out << ", ";
errors += argv_[idx]->emit(out, ent, scope);
}
out << ")";
}
errors += def_->emit_name(argv_, out, ent, scope);
out << " (";
def_->emit_args(argv_, out, ent, scope);
out << ")";
return errors;
}

View File

@ -305,9 +305,7 @@ static void import_ieee_use_std_logic_1164(ActiveScope*res, perm_string name)
bool all_flag = name=="all";
if (all_flag || name == "std_logic_vector") {
vector<VTypeArray::range_t> dims (1);
res->use_name(perm_string::literal("std_logic_vector"),
new VTypeArray(&primitive_STDLOGIC, dims, false));
res->use_name(perm_string::literal("std_logic_vector"), &primitive_STDLOGIC_VECTOR);
}
}
@ -393,22 +391,23 @@ const VTypePrimitive primitive_STDLOGIC(VTypePrimitive::STDLOGIC, true);
const VTypePrimitive primitive_CHARACTER(VTypePrimitive::CHARACTER);
const VTypePrimitive primitive_TIME(VTypePrimitive::TIME);
static const VTypeArray primitive_BIT_VECTOR(&primitive_BIT, vector<VTypeArray::range_t> (1));
static const VTypeArray primitive_BOOL_VECTOR(&primitive_BOOLEAN, vector<VTypeArray::range_t> (1));
static const VTypeArray primitive_STRING(&primitive_CHARACTER, vector<VTypeArray::range_t> (1));
const VTypeArray primitive_BIT_VECTOR(&primitive_BIT, vector<VTypeArray::range_t> (1));
const VTypeArray primitive_BOOL_VECTOR(&primitive_BOOLEAN, vector<VTypeArray::range_t> (1));
const VTypeArray primitive_STDLOGIC_VECTOR(&primitive_STDLOGIC, vector<VTypeArray::range_t> (1));
const VTypeArray primitive_STRING(&primitive_CHARACTER, vector<VTypeArray::range_t> (1));
void generate_global_types(ActiveScope*res)
{
res->use_name(perm_string::literal("boolean"), &primitive_BOOLEAN);
res->use_name(perm_string::literal("bit"), &primitive_BIT);
res->use_name(perm_string::literal("integer"), &primitive_INTEGER);
res->use_name(perm_string::literal("real"), &primitive_REAL);
res->use_name(perm_string::literal("std_logic"), &primitive_STDLOGIC);
res->use_name(perm_string::literal("character"), &primitive_CHARACTER);
res->use_name(perm_string::literal("bit_vector"),&primitive_BIT_VECTOR);
res->use_name(perm_string::literal("string"), &primitive_STRING);
res->use_name(perm_string::literal("natural"), &primitive_NATURAL);
res->use_name(perm_string::literal("time"), &primitive_TIME);
res->use_name(perm_string::literal("boolean"), &primitive_BOOLEAN);
res->use_name(perm_string::literal("bit"), &primitive_BIT);
res->use_name(perm_string::literal("bit_vector"), &primitive_BIT_VECTOR);
res->use_name(perm_string::literal("integer"), &primitive_INTEGER);
res->use_name(perm_string::literal("real"), &primitive_REAL);
res->use_name(perm_string::literal("std_logic"), &primitive_STDLOGIC);
res->use_name(perm_string::literal("character"), &primitive_CHARACTER);
res->use_name(perm_string::literal("string"), &primitive_STRING);
res->use_name(perm_string::literal("natural"), &primitive_NATURAL);
res->use_name(perm_string::literal("time"), &primitive_TIME);
}
void emit_std_types(ostream&out)
@ -423,12 +422,12 @@ bool is_global_type(perm_string name)
{
if (name == "boolean") return true;
if (name == "bit") return true;
if (name == "bit_vector") return true;
if (name == "integer") return true;
if (name == "real") return true;
if (name == "std_logic") return true;
if (name == "std_logic_vector") return true;
if (name == "character") return true;
if (name == "bit_vector") return true;
if (name == "string") return true;
if (name == "natural") return true;
if (name == "signed") return true;

View File

@ -76,6 +76,7 @@ const char NOTICE[] =
# include "compiler.h"
# include "library.h"
# include "std_funcs.h"
# include "parse_api.h"
# include "vtype.h"
# include <fstream>
@ -184,6 +185,8 @@ int main(int argc, char*argv[])
library_set_work_path(work_path);
preload_global_types();
preload_std_funcs();
int errors = 0;
for (int idx = optind ; idx < argc ; idx += 1) {

View File

@ -39,6 +39,7 @@
# include "package.h"
# include "vsignal.h"
# include "vtype.h"
# include "std_funcs.h"
# include <cstdarg>
# include <cstring>
# include <list>
@ -146,6 +147,7 @@ void parser_cleanup(void)
{
delete_design_entities();
delete_global_scope();
delete_std_funcs();
lex_strings.cleanup();
}

View File

@ -22,6 +22,7 @@
# include "package.h"
# include "subprogram.h"
# include "entity.h"
# include "std_funcs.h"
# include <algorithm>
# include <iostream>
# include <iterator>
@ -185,7 +186,7 @@ SubprogramHeader* ScopeBase::find_subprogram(perm_string name) const
if (cur != use_subprograms_.end())
return cur->second;
return 0;
return find_std_subprogram(name);
}
const VTypeEnum* ScopeBase::is_enum_name(perm_string name) const

View File

@ -149,7 +149,6 @@ int SignalSeqAssignment::elaborate(Entity*ent, ScopeBase*scope)
// Elaborate the r-value expressions.
for (list<Expression*>::iterator cur = waveform_.begin()
; cur != waveform_.end() ; ++cur) {
errors += (*cur)->elaborate_expr(ent, scope, lval_type);
}

226
vhdlpp/std_funcs.cc Normal file
View File

@ -0,0 +1,226 @@
/*
* Copyright CERN 2015
* @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
* 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.
*/
#include "std_funcs.h"
#include "vtype.h"
#include "scope.h"
static std::map<perm_string,SubprogramHeader*> std_subprograms;
// Special case: to_integer function
static class SubprogramToInteger : public SubprogramHeader {
public:
SubprogramToInteger()
: SubprogramHeader(perm_string::literal("to_integer"), NULL, &primitive_REAL) {
ports_ = new std::list<InterfacePort*>();
ports_->push_back(new InterfacePort(&primitive_INTEGER));
}
bool is_std() const { return true; }
int emit_name(const std::vector<Expression*>&argv,
std::ostream&out, Entity*ent, ScopeBase*scope) const {
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<const VTypeArray*>(type);
if(array) {
signed_flag = array->signed_vector();
} else {
cerr << get_fileline() << ": sorry: Could not determine the "
<< "expression sign. Output may be erroneous." << endl;
return 1;
}
out << (signed_flag ? "$signed" : "$unsigned");
return 0;
}
}*fn_to_integer;
// Special case: size casting (e.g. conv_std_logic_vector() / resize()).
static class SubprogramSizeCast : public SubprogramHeader {
public:
SubprogramSizeCast(perm_string nam)
: SubprogramHeader(nam, NULL, &primitive_STDLOGIC_VECTOR) {
ports_ = new std::list<InterfacePort*>();
ports_->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR));
ports_->push_back(new InterfacePort(&primitive_INTEGER));
}
bool is_std() const { return true; }
int emit_name(const std::vector<Expression*>&argv,
std::ostream&out, Entity*ent, ScopeBase*scope) const {
int64_t use_size;
bool rc = argv[1]->evaluate(ent, scope, use_size);
if(!rc) {
cerr << get_fileline() << ": sorry: Could not evaluate the "
<< "expression size. Size casting impossible." << endl;
return 1;
}
out << use_size << "'";
return 0;
}
int emit_args(const std::vector<Expression*>&argv,
std::ostream&out, Entity*ent, ScopeBase*scope) const {
return argv[0]->emit(out, ent, scope);
}
}*fn_conv_std_logic_vector, *fn_resize;
static SubprogramBuiltin*fn_std_logic_vector;
static SubprogramBuiltin*fn_to_unsigned;
static SubprogramBuiltin*fn_unsigned;
static SubprogramBuiltin*fn_integer;
static SubprogramBuiltin*fn_rising_edge;
static SubprogramBuiltin*fn_falling_edge;
static SubprogramBuiltin*fn_and_reduce;
static SubprogramBuiltin*fn_or_reduce;
void preload_std_funcs(void)
{
/* numeric_std library
* function unsigned
*/
std::list<InterfacePort*>*fn_unsigned_args = new std::list<InterfacePort*>();
fn_unsigned_args->push_back(new InterfacePort(&primitive_INTEGER));
fn_unsigned = new SubprogramBuiltin(perm_string::literal("unsigned"),
perm_string::literal("$unsigned"),
fn_unsigned_args, &primitive_UNSIGNED);
std_subprograms[fn_unsigned->name()] = fn_unsigned;
/* function integer
*/
std::list<InterfacePort*>*fn_integer_args = new std::list<InterfacePort*>();
fn_integer_args->push_back(new InterfacePort(&primitive_INTEGER));
fn_integer = new SubprogramBuiltin(perm_string::literal("integer"),
perm_string::literal("$signed"),
fn_integer_args, &primitive_INTEGER);
std_subprograms[fn_integer->name()] = fn_integer;
/* function std_logic_vector
Special case: The std_logic_vector function casts its
argument to std_logic_vector. Internally, we don't
have to do anything for that to work.
*/
std::list<InterfacePort*>*fn_std_logic_vector_args = new std::list<InterfacePort*>();
fn_std_logic_vector_args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR));
fn_std_logic_vector = new SubprogramBuiltin(perm_string::literal("std_logic_vector"),
empty_perm_string,
fn_std_logic_vector_args, &primitive_STDLOGIC_VECTOR);
std_subprograms[fn_std_logic_vector->name()] = fn_std_logic_vector;
/* function resize
*/
fn_resize = new SubprogramSizeCast(perm_string::literal("resize"));
std_subprograms[fn_resize->name()] = fn_resize;
/* function conv_std_logic_vector
*/
fn_conv_std_logic_vector = new SubprogramSizeCast(perm_string::literal("conv_std_logic_vector"));
std_subprograms[fn_conv_std_logic_vector->name()] = fn_conv_std_logic_vector;
/* numeric_bit library
* function to_integer (arg: unsigned) return natural;
* function to_integer (arg: signed) return integer;
*/
fn_to_integer = new SubprogramToInteger();
std_subprograms[fn_to_integer->name()] = fn_to_integer;
/* std_logic_1164 library
* function rising_edge (signal s : std_ulogic) return boolean;
*/
std::list<InterfacePort*>*fn_rising_edge_args = new std::list<InterfacePort*>();
fn_rising_edge_args->push_back(new InterfacePort(&primitive_STDLOGIC));
fn_rising_edge = new SubprogramBuiltin(perm_string::literal("rising_edge"),
perm_string::literal("$ivlh_rising_edge"),
fn_rising_edge_args, &primitive_BOOLEAN);
std_subprograms[fn_rising_edge->name()] = fn_rising_edge;
/* std_logic_1164 library
* function falling_edge (signal s : std_ulogic) return boolean;
*/
std::list<InterfacePort*>*fn_falling_edge_args = new std::list<InterfacePort*>();
fn_falling_edge_args->push_back(new InterfacePort(&primitive_STDLOGIC));
fn_falling_edge = new SubprogramBuiltin(perm_string::literal("falling_edge"),
perm_string::literal("$ivlh_falling_edge"),
fn_falling_edge_args, &primitive_BOOLEAN);
std_subprograms[fn_falling_edge->name()] = fn_falling_edge;
/* reduce_pack library
* function or_reduce(arg : std_logic_vector) return std_logic;
*/
std::list<InterfacePort*>*fn_or_reduce_args = new std::list<InterfacePort*>();
fn_or_reduce_args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR));
fn_or_reduce = new SubprogramBuiltin(perm_string::literal("or_reduce"),
perm_string::literal("|"),
fn_or_reduce_args, &primitive_STDLOGIC);
std_subprograms[fn_or_reduce->name()] = fn_or_reduce;
/* reduce_pack library
* function and_reduce(arg : std_logic_vector) return std_logic;
*/
std::list<InterfacePort*>*fn_and_reduce_args = new std::list<InterfacePort*>();
fn_and_reduce_args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR));
fn_and_reduce = new SubprogramBuiltin(perm_string::literal("and_reduce"),
perm_string::literal("&"),
fn_and_reduce_args, &primitive_STDLOGIC);
std_subprograms[fn_and_reduce->name()] = fn_and_reduce;
/* fixed_pkg library
* function to_unsigned (
* arg : ufixed; -- fixed point input
* constant size : natural) -- length of output
* return unsigned;
*/
std::list<InterfacePort*>*fn_to_unsigned_args = new std::list<InterfacePort*>();
fn_to_unsigned_args->push_back(new InterfacePort(&primitive_REAL));
fn_to_unsigned_args->push_back(new InterfacePort(&primitive_NATURAL));
fn_to_unsigned = new SubprogramBuiltin(perm_string::literal("to_unsigned"),
perm_string::literal("$ivlh_to_unsigned"),
fn_to_unsigned_args, &primitive_UNSIGNED);
std_subprograms[fn_to_unsigned->name()] = fn_to_unsigned;
}
void delete_std_funcs()
{
for(std::map<perm_string,SubprogramHeader*>::iterator it = std_subprograms.begin();
it != std_subprograms.end(); ++it) {
delete it->second;
}
}
SubprogramHeader*find_std_subprogram(perm_string name)
{
map<perm_string,SubprogramHeader*>::const_iterator cur = std_subprograms.find(name);
if (cur != std_subprograms.end())
return cur->second;
return NULL;
}

34
vhdlpp/std_funcs.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef IVL_std_funcs_H
#define IVL_std_funcs_H
/*
* Copyright CERN 2015
* @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
* 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.
*/
#include "subprogram.h"
// Generates subprogram headers for standard VHDL library functions.
void preload_std_funcs();
// Destroys subprogram headers for standard VHDL library functions.
void delete_std_funcs();
// Returns subprogram header for a requested function or NULL if it does not exist.
SubprogramHeader*find_std_subprogram(perm_string name);
#endif /* IVL_std_funcs_H */

View File

@ -82,6 +82,7 @@ SubprogramHeader::SubprogramHeader(perm_string nam, list<InterfacePort*>*ports,
SubprogramHeader::~SubprogramHeader()
{
delete body_;
delete ports_;
}
bool SubprogramHeader::compare_specification(SubprogramHeader*that) const
@ -170,7 +171,7 @@ void SubprogramHeader::set_body(SubprogramBody*bdy)
}
SubprogramHeader*SubprogramHeader::make_instance(std::vector<Expression*> arguments,
ScopeBase*scope) {
ScopeBase*scope) const {
assert(arguments.size() == ports_->size());
std::list<InterfacePort*>*ports = new std::list<InterfacePort*>;
@ -293,3 +294,13 @@ void SubprogramHeader::write_to_stream(ostream&fd) const
fd << ") return ";
return_type_->write_to_stream(fd);
}
SubprogramBuiltin::SubprogramBuiltin(perm_string vhdl_name, perm_string sv_name,
std::list<InterfacePort*>*ports, const VType*return_type)
: SubprogramHeader(vhdl_name, ports, return_type), sv_name_(sv_name)
{
}
SubprogramBuiltin::~SubprogramBuiltin()
{
}

View File

@ -64,7 +64,7 @@ class SubprogramHeader : public LineInfo {
public:
SubprogramHeader(perm_string name, std::list<InterfacePort*>*ports,
const VType*return_type);
~SubprogramHeader();
virtual ~SubprogramHeader();
// Return true if the specification (name, types, ports)
// matches this subprogram and that subprogram.
@ -80,16 +80,32 @@ class SubprogramHeader : public LineInfo {
// Checks if either return type or parameters are unbounded vectors.
bool unbounded() const;
inline SubprogramBody*body() { return body_; }
// Is the subprogram coming from the standard library?
virtual bool is_std() const { return false; }
inline SubprogramBody*body() const { return body_; }
void set_body(SubprogramBody*bdy);
inline perm_string name() { return name_; }
inline perm_string name() const { return name_; }
// Function name used in the emission step. The main purpose of this
// method is to handle functions offered by standard VHDL libraries.
// Allows to return different function names depending on the arguments
// (think of size casting or signed/unsigned functions).
virtual int emit_name(const std::vector<Expression*>&,
std::ostream&out, Entity*, ScopeBase*) const;
// Emit arguments for a specific call. It allows to reorder or skip
// some of the arguments if function signature is different in
// SystemVerilog compared to VHDL.
virtual int emit_args(const std::vector<Expression*>&argv,
std::ostream&out, Entity*, ScopeBase*) 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.
SubprogramHeader*make_instance(std::vector<Expression*> arguments, ScopeBase*scope);
SubprogramHeader*make_instance(std::vector<Expression*> arguments, ScopeBase*scope) const;
// Emit header as it would show up in a package.
int emit_package(std::ostream&fd) const;
@ -97,7 +113,7 @@ class SubprogramHeader : public LineInfo {
void write_to_stream(std::ostream&fd) const;
void dump(std::ostream&fd) const;
private:
protected:
// Tries to set the return type to a fixed type. VHDL functions that
// return std_logic_vectors do not specify its length, as SystemVerilog
// demands.
@ -112,4 +128,21 @@ class SubprogramHeader : public LineInfo {
const ScopeBase*parent_;
};
// Class to define functions headers defined in the standard VHDL libraries.
class SubprogramBuiltin : public SubprogramHeader
{
public:
SubprogramBuiltin(perm_string vhdl_name, perm_string sv_name,
std::list<InterfacePort*>*ports, const VType*return_type);
~SubprogramBuiltin();
bool is_std() const { return true; }
int emit_name(const std::vector<Expression*>&, std::ostream&out, Entity*, ScopeBase*) const;
private:
// SystemVerilog counterpart function name
perm_string sv_name_;
};
#endif /* IVL_subprogram_H */

View File

@ -116,3 +116,11 @@ int SubprogramHeader::emit_args(const std::vector<Expression*>&argv,
return errors;
}
int SubprogramBuiltin::emit_name(const std::vector<Expression*>&,
std::ostream&out, Entity*, ScopeBase*) const
{
// do not escape the names for builtin functions
out << sv_name_;
return 0;
}

View File

@ -180,15 +180,6 @@ class VTypePrimitive : public VType {
bool packed_;
};
extern const VTypePrimitive primitive_BOOLEAN;
extern const VTypePrimitive primitive_BIT;
extern const VTypePrimitive primitive_INTEGER;
extern const VTypePrimitive primitive_NATURAL;
extern const VTypePrimitive primitive_REAL;
extern const VTypePrimitive primitive_STDLOGIC;
extern const VTypePrimitive primitive_CHARACTER;
extern const VTypePrimitive primitive_TIME;
/*
* An array is a compound N-dimensional array of element type. The
* construction of the array is from an element type and a vector of
@ -391,4 +382,18 @@ class VTypeDef : public VType {
const VType*type_;
};
extern const VTypePrimitive primitive_BOOLEAN;
extern const VTypePrimitive primitive_BIT;
extern const VTypePrimitive primitive_INTEGER;
extern const VTypePrimitive primitive_NATURAL;
extern const VTypePrimitive primitive_REAL;
extern const VTypePrimitive primitive_STDLOGIC;
extern const VTypePrimitive primitive_CHARACTER;
extern const VTypePrimitive primitive_TIME;
extern const VTypeArray primitive_BIT_VECTOR;
extern const VTypeArray primitive_BOOL_VECTOR;
extern const VTypeArray primitive_STDLOGIC_VECTOR;
extern const VTypeArray primitive_STRING;
#endif /* IVL_vtype_H */