vhdlpp: Refactored the way of handling standard VHDL library functions.
This commit is contained in:
parent
356a09d295
commit
169228ad0f
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Reference in New Issue