Merge pull request #71 from orsonmmz/procedure_calls

Procedure calls
This commit is contained in:
Stephen Williams 2015-06-30 08:27:51 -07:00
commit 935ee6137d
40 changed files with 1283 additions and 736 deletions

View File

@ -2009,6 +2009,12 @@ static bool check_dimension(const NetExpr*dim_expr, long &dim)
static bool get_array_info(const NetExpr*arg, long dim,
long &left, long &right, bool&defer)
{
if (const NetEConstParam*param = dynamic_cast<const NetEConstParam*>(arg)) {
assert(dim == 1);
left = param->expr_width() - 1;
right = 0;
return false;
}
/* The argument must be a signal that has enough dimensions. */
const NetESignal*esig = dynamic_cast<const NetESignal*>(arg);
if (esig == 0) return true;

View File

@ -4169,6 +4169,9 @@ port_declaration
use_type = NetNet::IMPLICIT_REG;
} else if (dynamic_cast<struct_type_t*> ($4)) {
use_type = NetNet::IMPLICIT_REG;
} else if (enum_type_t*etype = dynamic_cast<enum_type_t*> ($4)) {
if(etype->base_type == IVL_VT_LOGIC)
use_type = NetNet::IMPLICIT_REG;
}
}
ptmp = pform_module_port_reference(name, @2.text, @2.first_line);

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 std_types.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

@ -195,50 +195,6 @@ int ProcessStatement::rewrite_as_always_edge_(Entity*, Architecture*)
return -1;
const Expression*ce_raw = stmt->peek_condition();
// Now we have matched this pattern:
// process(<expr>) begin if <ce_raw>...
// The <ce_raw> is the condition.
if (const ExpFunc*ce_func = dynamic_cast<const ExpFunc*>(ce_raw)) {
if (ce_func->func_args() != 1)
return -1;
if (ce_func->func_name()!="rising_edge" && ce_func->func_name()!="falling_edge")
return -1;
if (! se->symbolic_compare(ce_func->func_arg(0)))
return -1;
// We've matched this pattern:
// process(<se>) if (rising_edge(<se>)) then ...
// and we can convert it to:
// always @(posedge <se>) ...
ExpEdge::fun_t use_edge;
if (ce_func->func_name()=="rising_edge")
use_edge = ExpEdge::POSEDGE;
else if (ce_func->func_name()=="falling_edge")
use_edge = ExpEdge::NEGEDGE;
else
use_edge = ExpEdge::ANYEDGE;
// Replace the sensitivity expression with an edge
// expression. The ExpEdge expression signals that this
// is an always-@(edge) statement.
ExpEdge*edge = new ExpEdge(use_edge, se);
assert(sensitivity_list_.size() == 1);
sensitivity_list_.pop_front();
sensitivity_list_.push_front(edge);
// Replace the statement with the body of the always
// statement, which is the true clause of the top "if"
// statement. There should be no "else" clause.
assert(statements_list_.size() == 1);
statements_list_.pop_front();
stmt->extract_true(statements_list_);
delete stmt;
return 0;
}
// Here we expect the condition to be
// <name>'event AND <name>='1'.

View File

@ -101,7 +101,7 @@ int Architecture::emit(ostream&out, Entity*entity)
errors += emit_signals(out, entity, this);
errors += emit_variables(out, entity, this);
for (map<perm_string,Subprogram*>::const_iterator cur = cur_subprograms_.begin()
for (map<perm_string,SubprogramHeader*>::const_iterator cur = cur_subprograms_.begin()
; cur != cur_subprograms_.end() ; ++ cur) {
// Do not emit unbounded functions, we will just need fixed instances later
if(!cur->second->unbounded())

View File

@ -150,17 +150,21 @@ void Scope::dump_scope(ostream&out) const
}
// Dump subprograms
out << " -- Imported Subprograms" << endl;
for (map<perm_string,Subprogram*>::const_iterator cur = use_subprograms_.begin()
for (map<perm_string,SubprogramHeader*>::const_iterator cur = use_subprograms_.begin()
; cur != use_subprograms_.end() ; ++cur) {
out << " subprogram " << cur->first << " is" << endl;
cur->second->dump(out);
if(cur->second->body())
cur->second->body()->dump(out);
out << " end subprogram " << cur->first << endl;
}
out << " -- Subprograms from this scope" << endl;
for (map<perm_string,Subprogram*>::const_iterator cur = cur_subprograms_.begin()
for (map<perm_string,SubprogramHeader*>::const_iterator cur = cur_subprograms_.begin()
; cur != cur_subprograms_.end() ; ++cur) {
out << " subprogram " << cur->first << " is" << endl;
cur->second->dump(out);
if(cur->second->body())
cur->second->body()->dump(out);
out << " end subprogram " << cur->first << endl;
}
// Dump component declarations
@ -279,22 +283,14 @@ void ExpCharacter::dump(ostream&out, int indent) const
void ExpConditional::dump(ostream&out, int indent) const
{
out << setw(indent) << "" << "Conditional expression at "<< get_fileline() << endl;
out << setw(indent) << "" << " when:" << endl;
cond_->dump(out, indent+4);
out << setw(indent) << "" << " do:" << endl;
for (list<Expression*>::const_iterator cur = true_clause_.begin()
; cur != true_clause_.end() ; ++cur) {
(*cur)->dump(out, indent+4);
}
for (list<else_t*>::const_iterator cur = else_clause_.begin()
; cur != else_clause_.end() ; ++cur) {
for (list<case_t*>::const_iterator cur = options_.begin()
; cur != options_.end() ; ++cur) {
(*cur)->dump(out, indent);
}
}
void ExpConditional::else_t::dump(ostream&out, int indent) const
void ExpConditional::case_t::dump(ostream&out, int indent) const
{
out << setw(indent) << "" << "when:" << endl;
if (cond_) cond_->dump(out, indent+4);
@ -475,7 +471,20 @@ ostream& ExpReal::dump_inline(ostream&out) const
return out;
}
void Subprogram::dump(ostream&fd) const
void SubprogramBody::dump(ostream&fd) const
{
if (statements_== 0 || statements_->empty()) {
fd << " <no definition>" << endl;
} else {
for (list<SequentialStmt*>::const_iterator cur = statements_->begin()
; cur != statements_->end() ; ++cur) {
SequentialStmt*curp = *cur;
curp->dump(fd, 8);
}
}
}
void SubprogramHeader::dump(ostream&fd) const
{
fd << " " << name_;
@ -501,14 +510,4 @@ void Subprogram::dump(ostream&fd) const
fd << " return ";
return_type_->show(fd);
fd << endl;
if (statements_== 0 || statements_->empty()) {
fd << " <no definition>" << endl;
} else {
for (list<SequentialStmt*>::const_iterator cur = statements_->begin()
; cur != statements_->end() ; ++cur) {
SequentialStmt*curp = *cur;
curp->dump(fd, 8);
}
}
}

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

@ -129,12 +129,21 @@ ExpAggregate::ExpAggregate(std::list<element_t*>*el)
elements_[idx++] = el->front();
el->pop_front();
}
delete el;
}
ExpAggregate::~ExpAggregate()
{
for (size_t idx = 0 ; idx < elements_.size() ; idx += 1)
delete elements_[idx];
for(std::vector<element_t*>::iterator it = elements_.begin();
it != elements_.end(); ++it) {
delete *it;
}
for(std::vector<choice_element>::iterator it = aggregate_.begin();
it != aggregate_.end(); ++it) {
delete it->choice;
delete it->expr;
}
}
Expression* ExpAggregate::clone() const
@ -301,84 +310,53 @@ void ExpConcat::visit(ExprVisitor& func)
}
ExpConditional::ExpConditional(Expression*co, list<Expression*>*tru,
list<ExpConditional::else_t*>*fal)
: cond_(co)
list<ExpConditional::case_t*>*options)
{
if (tru) true_clause_.splice(true_clause_.end(), *tru);
if (fal) else_clause_.splice(else_clause_.end(), *fal);
if(co && tru) options_.push_back(new case_t(co, tru));
if(options) options_.splice(options_.end(), *options);
}
ExpConditional::~ExpConditional()
{
delete cond_;
while (! true_clause_.empty()) {
Expression*tmp = true_clause_.front();
true_clause_.pop_front();
delete tmp;
}
while (! else_clause_.empty()) {
else_t*tmp = else_clause_.front();
else_clause_.pop_front();
while (!options_.empty()) {
case_t*tmp = options_.front();
options_.pop_front();
delete tmp;
}
}
Expression*ExpConditional::clone() const
{
std::list<Expression*>*new_true_clause = NULL;
if(!true_clause_.empty()) {
new_true_clause = new std::list<Expression*>();
std::list<case_t*>*new_options = NULL;
if(!options_.empty()) {
new_options = new std::list<case_t*>();
for(std::list<Expression*>::const_iterator it = true_clause_.begin();
it != true_clause_.end(); ++it) {
new_true_clause->push_back((*it)->clone());
for(std::list<case_t*>::const_iterator it = options_.begin();
it != options_.end(); ++it) {
new_options->push_back(new case_t(**it));
}
}
std::list<else_t*>*new_else_clause = NULL;
if(!else_clause_.empty()) {
new_else_clause = new std::list<else_t*>();
for(std::list<else_t*>::const_iterator it = else_clause_.begin();
it != else_clause_.end(); ++it) {
new_else_clause->push_back(new else_t(**it));
}
}
return new ExpConditional(cond_->clone(), new_true_clause, new_else_clause);
return new ExpConditional(NULL, NULL, new_options);
}
void ExpConditional::visit(ExprVisitor& func)
{
if(!true_clause_.empty()) {
for(std::list<Expression*>::iterator it = true_clause_.begin();
it != true_clause_.end(); ++it) {
(*it)->visit(func);
}
}
if(!else_clause_.empty()) {
for(std::list<else_t*>::iterator it = else_clause_.begin();
it != else_clause_.end(); ++it) {
std::list<Expression*>& else_clause = (*it)->extract_true_clause();
for(std::list<Expression*>::iterator jt = else_clause.begin();
jt != else_clause.end(); ++jt) {
(*jt)->visit(func);
}
}
for(std::list<case_t*>::iterator it = options_.begin();
it != options_.end(); ++it) {
(*it)->visit(func);
}
func(this);
}
ExpConditional::else_t::else_t(Expression*cond, std::list<Expression*>*tru)
ExpConditional::case_t::case_t(Expression*cond, std::list<Expression*>*tru)
: cond_(cond)
{
if (tru) true_clause_.splice(true_clause_.end(), *tru);
}
ExpConditional::else_t::else_t(const else_t&other)
ExpConditional::case_t::case_t(const case_t&other)
: LineInfo(other)
{
cond_ = other.cond_->clone();
@ -388,7 +366,7 @@ ExpConditional::else_t::else_t(const else_t&other)
}
}
ExpConditional::else_t::~else_t()
ExpConditional::case_t::~case_t()
{
delete cond_;
while (! true_clause_.empty()) {
@ -398,6 +376,49 @@ ExpConditional::else_t::~else_t()
}
}
ExpSelected::ExpSelected(Expression*selector, std::list<case_t*>*options)
: ExpConditional(NULL, NULL, options), selector_(selector)
{
// Currently condition field contains only value,
// so substitute it with a comparison to create a valid condition
for(std::list<case_t*>::iterator it = options_.begin();
it != options_.end(); ++it) {
Expression*cond = (*it)->condition();
if(cond)
(*it)->set_condition(new ExpRelation(ExpRelation::EQ, selector_->clone(), cond));
}
}
ExpSelected::~ExpSelected()
{
}
Expression*ExpSelected::clone() const
{
std::list<case_t*>*new_options = NULL;
if(!options_.empty()) {
new_options = new std::list<case_t*>();
for(std::list<case_t*>::const_iterator it = options_.begin();
it != options_.end(); ++it) {
new_options->push_back(new case_t(**it));
}
}
return new ExpSelected(selector_->clone(), new_options);
}
void ExpConditional::case_t::visit(ExprVisitor& func)
{
if(cond_)
func(cond_);
for(std::list<Expression*>::iterator it = true_clause_.begin();
it != true_clause_.end(); ++it) {
func(*it);
}
}
ExpEdge::ExpEdge(ExpEdge::fun_t typ, Expression*op)
: ExpUnary(op), fun_(typ)
@ -527,6 +548,7 @@ ExpName::ExpName(ExpName*prefix, perm_string nn, Expression*msb, Expression*lsb)
ExpName::~ExpName()
{
delete index_;
delete lsb_;
}
bool ExpName::symbolic_compare(const Expression*that) const

View File

@ -32,7 +32,7 @@
class prange_t;
class Entity;
class ScopeBase;
class Subprogram;
class SubprogramHeader;
class VType;
class VTypeArray;
class VTypePrimitive;
@ -460,17 +460,21 @@ class ExpConcat : public Expression {
class ExpConditional : public Expression {
public:
class else_t : public LineInfo {
class case_t : public LineInfo {
public:
else_t(Expression*cond, std::list<Expression*>*tru);
else_t(const else_t&other);
~else_t();
case_t(Expression*cond, std::list<Expression*>*tru);
case_t(const case_t&other);
~case_t();
inline Expression*condition() { return cond_; }
inline void set_condition(Expression*cond) { cond_ = cond; }
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*lt);
int emit_when_else(ostream&out, Entity*ent, ScopeBase*scope);
int emit_else(ostream&out, Entity*ent, ScopeBase*scope);
int emit_option(ostream&out, Entity*ent, ScopeBase*scope);
int emit_default(ostream&out, Entity*ent, ScopeBase*scope);
void dump(ostream&out, int indent = 0) const;
std::list<Expression*>& extract_true_clause() { return true_clause_; }
void visit(ExprVisitor& func);
private:
Expression*cond_;
@ -479,10 +483,10 @@ class ExpConditional : public Expression {
public:
ExpConditional(Expression*cond, std::list<Expression*>*tru,
std::list<else_t*>*fal);
~ExpConditional();
std::list<case_t*>*options);
virtual ~ExpConditional();
Expression*clone() const;
virtual Expression*clone() const;
const VType*probe_type(Entity*ent, ScopeBase*scope) const;
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
@ -491,10 +495,22 @@ class ExpConditional : public Expression {
void dump(ostream&out, int indent = 0) const;
void visit(ExprVisitor& func);
protected:
std::list<case_t*> options_;
};
/*
* Expression to handle selected assignments (with .. select target <= value when ..)
*/
class ExpSelected : public ExpConditional {
public:
ExpSelected(Expression*selector, std::list<case_t*>*options);
~ExpSelected();
Expression*clone() const;
private:
Expression*cond_;
std::list<Expression*> true_clause_;
std::list<else_t*> else_clause_;
Expression*selector_;
};
/*
@ -548,7 +564,7 @@ class ExpFunc : public Expression {
private:
perm_string name_;
std::vector<Expression*> argv_;
Subprogram*def_;
SubprogramHeader*def_;
};
class ExpInteger : public Expression {
@ -662,6 +678,11 @@ class ExpName : public Expression {
public:
index_t(Expression*idx, Expression*size, Expression*offset = NULL) :
idx_(idx), size_(size), offset_(offset) {}
~index_t() {
delete idx_;
delete size_;
delete offset_;
}
int emit(ostream&out, Entity*ent, ScopeBase*scope);

View File

@ -25,6 +25,7 @@
# include "vsignal.h"
# include "subprogram.h"
# include "library.h"
# include "std_types.h"
# include <iostream>
# include <typeinfo>
# include "parse_types.h"
@ -714,22 +715,16 @@ int ExpConditional::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltyp
/* Note that the type for the condition expression need not
have anything to do with the type of this expression. */
errors += cond_->elaborate_expr(ent, scope, 0);
for (list<Expression*>::const_iterator cur = true_clause_.begin()
; cur != true_clause_.end() ; ++cur) {
errors += (*cur)->elaborate_expr(ent, scope, ltype);
}
for (list<else_t*>::const_iterator cur = else_clause_.begin()
; cur != else_clause_.end() ; ++cur) {
for (list<case_t*>::const_iterator cur = options_.begin()
; cur != options_.end() ; ++cur) {
errors += (*cur)->elaborate_expr(ent, scope, ltype);
}
return errors;
}
int ExpConditional::else_t::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype)
int ExpConditional::case_t::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype)
{
int errors = 0;
@ -744,53 +739,22 @@ int ExpConditional::else_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);
}
Subprogram*prog = scope->find_subprogram(name_);
if(!prog)
prog = library_find_subprogram(name_);
if(!prog)
return NULL;
return prog->peek_return_type();
}
@ -799,7 +763,7 @@ int ExpFunc::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*)
int errors = 0;
ivl_assert(*this, scope);
Subprogram*prog = scope->find_subprogram(name_);
SubprogramHeader*prog = scope->find_subprogram(name_);
if(!prog)
prog = library_find_subprogram(name_);
@ -818,86 +782,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
Subprogram*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
@ -1037,6 +940,10 @@ const VType* ExpName::probe_type(Entity*ent, ScopeBase*scope) const
return type;
}
if (const InterfacePort*port = scope->find_param(name_)) {
return port->type;
}
if ((type = scope->is_enum_name(name_))) {
return type;
}
@ -1052,13 +959,22 @@ const VType* ExpName::fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*)co
return probe_type(ent, scope);
}
int ExpName::elaborate_expr(Entity*, ScopeBase*, const VType*ltype)
int ExpName::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype)
{
if (ltype) {
ivl_assert(*this, ltype != 0);
set_type(ltype);
}
if(prefix_.get())
prefix_.get()->elaborate_expr(ent, scope, NULL);
if(index_)
index_->elaborate_expr(ent, scope, &primitive_INTEGER);
if(lsb_)
lsb_->elaborate_expr(ent, scope, &primitive_INTEGER);
return 0;
}
@ -1069,7 +985,7 @@ const VType* ExpNameALL::probe_type(Entity*, ScopeBase*) const
const VType* ExpRelation::probe_type(Entity*, ScopeBase*) const
{
return &primitive_BOOLEAN;
return &type_BOOLEAN;
}
int ExpRelation::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype)

View File

@ -23,7 +23,8 @@
# include "vtype.h"
# include "architec.h"
# include "package.h"
# include "subprogram.h"
# include "std_funcs.h"
# include "std_types.h"
# include "parse_types.h"
# include <typeinfo>
# include <iostream>
@ -481,45 +482,33 @@ int ExpConditional::emit(ostream&out, Entity*ent, ScopeBase*scope)
{
int errors = 0;
out << "(";
errors += cond_->emit(out, ent, scope);
out << ")? (";
if (true_clause_.size() > 1) {
cerr << get_fileline() << ": sorry: Multiple expression waveforms not supported here." << endl;
errors += 1;
}
Expression*tmp = true_clause_.front();
errors += tmp->emit(out, ent, scope);
out << ") : (";
// Draw out any when-else expressions. These are all the else_
// clauses besides the last.
if (else_clause_.size() > 1) {
list<else_t*>::iterator last = else_clause_.end();
-- last;
if (options_.size() > 1) {
list<case_t*>::iterator last = options_.end();
--last;
for (list<else_t*>::iterator cur = else_clause_.begin()
for (list<case_t*>::iterator cur = options_.begin()
; cur != last ; ++cur) {
errors += (*cur) ->emit_when_else(out, ent, scope);
errors += (*cur)->emit_option(out, ent, scope);
}
}
}
errors += else_clause_.back()->emit_else(out, ent, scope);
errors += options_.back()->emit_default(out, ent, scope);
out << ")";
// The emit_when_else() functions do not close the last
// The emit_option() functions do not close the last
// parentheses so that the following expression can be
// nested. But that means come the end, we have some
// expressions to close.
for (size_t idx = 1 ; idx < else_clause_.size() ; idx += 1)
for (size_t idx = 1 ; idx < options_.size() ; idx += 1)
out << ")";
return errors;
}
int ExpConditional::else_t::emit_when_else(ostream&out, Entity*ent, ScopeBase*scope)
int ExpConditional::case_t::emit_option(ostream&out, Entity*ent, ScopeBase*scope)
{
int errors = 0;
assert(cond_ != 0);
@ -541,7 +530,7 @@ int ExpConditional::else_t::emit_when_else(ostream&out, Entity*ent, ScopeBase*sc
return errors;
}
int ExpConditional::else_t::emit_else(ostream&out, Entity*ent, ScopeBase*scope)
int ExpConditional::case_t::emit_default(ostream&out, Entity*ent, ScopeBase*scope)
{
int errors = 0;
// Trailing else must have no condition.
@ -579,103 +568,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;
}
@ -767,6 +674,11 @@ int ExpName::emit(ostream&out, Entity*ent, ScopeBase*scope)
if(try_workarounds_(out, ent, scope, indices, field_size)) {
emit_workaround_(out, ent, scope, indices, field_size);
for(list<index_t*>::iterator it = indices.begin();
it != indices.end(); ++it)
{
delete *it;
}
return 0;
}
@ -847,7 +759,7 @@ bool ExpName::check_const_array_workaround_(const VTypeArray*arr,
data_size = element->get_width(scope);
if(data_size < 0)
return false;
indices.push_back(new index_t(index_, new ExpInteger(data_size)));
indices.push_back(new index_t(index_->clone(), new ExpInteger(data_size)));
return true;
}
@ -1044,7 +956,14 @@ int ExpUAbs::emit(ostream&out, Entity*ent, ScopeBase*scope)
int ExpUNot::emit(ostream&out, Entity*ent, ScopeBase*scope)
{
int errors = 0;
out << "~(";
const VType*op_type = peek_operand()->probe_type(ent, scope);
if(op_type && op_type->type_match(&type_BOOLEAN))
out << "!(";
else
out << "~(";
errors += emit_operand1(out, ent, scope);
out << ")";
return errors;

View File

@ -22,6 +22,7 @@
# include "parse_misc.h"
# include "compiler.h"
# include "package.h"
# include "std_types.h"
# include <fstream>
# include <list>
# include <map>
@ -72,9 +73,9 @@ void library_add_directory(const char*directory)
library_search_path.push_front(directory);
}
Subprogram*library_find_subprogram(perm_string name)
SubprogramHeader*library_find_subprogram(perm_string name)
{
Subprogram*subp = NULL;
SubprogramHeader*subp = NULL;
map<perm_string,struct library_contents>::const_iterator lib_it;
for(lib_it = libraries.begin(); lib_it != libraries.end(); ++lib_it) {
@ -305,9 +306,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);
}
}
@ -320,14 +319,10 @@ static void import_ieee_use_numeric_bit(ActiveScope*res, perm_string name)
bool all_flag = name=="all";
if (all_flag || name == "signed") {
vector<VTypeArray::range_t> dims (1);
res->use_name(perm_string::literal("signed"),
new VTypeArray(&primitive_STDLOGIC, dims, true));
res->use_name(perm_string::literal("signed"), &primitive_SIGNED);
}
if (all_flag || name == "unsigned") {
vector<VTypeArray::range_t> dims (1);
res->use_name(perm_string::literal("unsigned"),
new VTypeArray(&primitive_BIT, dims, false));
res->use_name(perm_string::literal("unsigned"), &primitive_UNSIGNED);
}
}
@ -336,14 +331,10 @@ static void import_ieee_use_numeric_std(ActiveScope*res, perm_string name)
bool all_flag = name=="all";
if (all_flag || name == "signed") {
vector<VTypeArray::range_t> dims (1);
res->use_name(perm_string::literal("signed"),
new VTypeArray(&primitive_STDLOGIC, dims, true));
res->use_name(perm_string::literal("signed"), &primitive_SIGNED);
}
if (all_flag || name == "unsigned") {
vector<VTypeArray::range_t> dims (1);
res->use_name(perm_string::literal("unsigned"),
new VTypeArray(&primitive_STDLOGIC, dims, false));
res->use_name(perm_string::literal("unsigned"), &primitive_UNSIGNED);
}
}
@ -384,59 +375,6 @@ static void import_std_use(const YYLTYPE&loc, ActiveScope*/*res*/, perm_string p
}
}
const VTypePrimitive primitive_BOOLEAN(VTypePrimitive::BOOLEAN, true);
const VTypePrimitive primitive_BIT(VTypePrimitive::BIT, true);
const VTypePrimitive primitive_INTEGER(VTypePrimitive::INTEGER);
const VTypePrimitive primitive_NATURAL(VTypePrimitive::NATURAL);
const VTypePrimitive primitive_REAL(VTypePrimitive::REAL);
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));
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);
}
void emit_std_types(ostream&out)
{
out << "`ifndef __VHDL_STD_TYPES" << endl;
out << "`define __VHDL_STD_TYPES" << endl;
out << "typedef enum bit { \\false , \\true } boolean ;" << endl;
out << "`endif" << endl;
}
bool is_global_type(perm_string name)
{
if (name == "boolean") return true;
if (name == "bit") 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;
if (name == "unsigned") return true;
if (name == "time") return true;
return false;
}
void library_set_work_path(const char*path)
{
assert(library_work_path == 0);

View File

@ -19,15 +19,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
class Subprogram;
class SubprogramHeader;
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 void emit_std_types(ostream&out);
extern int emit_packages(void);
extern SubprogramHeader*library_find_subprogram(perm_string name);
#endif /* IVL_library_H */

View File

@ -76,6 +76,8 @@ const char NOTICE[] =
# include "compiler.h"
# include "library.h"
# include "std_funcs.h"
# include "std_types.h"
# include "parse_api.h"
# include "vtype.h"
# include <fstream>
@ -184,6 +186,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

@ -22,6 +22,7 @@
# include "entity.h"
# include "subprogram.h"
# include "parse_misc.h"
# include "std_types.h"
# include "ivl_assert.h"
Package::Package(perm_string n, const ActiveScope&ref)
@ -57,6 +58,11 @@ void Package::write_to_stream(ostream&fd) const
const VTypeDef*def = dynamic_cast<const VTypeDef*> (cur->second);
if (def == 0)
continue;
// Do not include global types in types dump
if (is_global_type(cur->first))
continue;
fd << "type " << cur->first << ";" << endl;
}
for (map<perm_string,const VType*>::const_iterator cur = cur_types_.begin()
@ -64,6 +70,11 @@ void Package::write_to_stream(ostream&fd) const
const VTypeDef*def = dynamic_cast<const VTypeDef*> (cur->second);
if (def == 0)
continue;
// Do not include global types in types dump
if (is_global_type(cur->first))
continue;
fd << "type " << cur->first << ";" << endl;
}
@ -111,9 +122,10 @@ void Package::write_to_stream(ostream&fd) const
fd << ";" << endl;
}
for (map<perm_string,Subprogram*>::const_iterator cur = cur_subprograms_.begin()
for (map<perm_string,SubprogramHeader*>::const_iterator cur = cur_subprograms_.begin()
; cur != cur_subprograms_.end() ; ++cur) {
cur->second->write_to_stream(fd);
fd << ";" << endl;
}
for (map<perm_string,ComponentBase*>::const_iterator cur = old_components_.begin()
@ -130,9 +142,14 @@ void Package::write_to_stream(ostream&fd) const
fd << "end package " << name_ << ";" << endl;
fd << "package body " << name_ << " is" << endl;
for (map<perm_string,Subprogram*>::const_iterator cur = cur_subprograms_.begin()
for (map<perm_string,SubprogramHeader*>::const_iterator cur = cur_subprograms_.begin()
; cur != cur_subprograms_.end() ; ++cur) {
cur->second->write_to_stream_body(fd);
SubprogramHeader*subp = cur->second;
if(subp->body()) {
subp->write_to_stream(fd);
fd << " is" << endl;
subp->body()->write_to_stream(fd);
}
}
fd << "end " << name_ << ";" << endl;
}

View File

@ -36,7 +36,7 @@ class Package : public Scope, public LineInfo {
perm_string name() const { return name_; }
Subprogram* recall_subprogram(perm_string name) const;
SubprogramHeader* recall_subprogram(perm_string name) const;
// This method writes a package header to a library file.
void write_to_stream(std::ostream&fd) const;

View File

@ -64,7 +64,7 @@ int Package::emit_package(ostream&fd) const
//}
fd << "package \\" << name() << " ;" << endl;
for (map<perm_string,Subprogram*>::const_iterator cur = cur_subprograms_.begin()
for (map<perm_string,SubprogramHeader*>::const_iterator cur = cur_subprograms_.begin()
; cur != cur_subprograms_.end() ; ++ cur) {
// Do not emit unbounded functions, we will just need fixed instances later
if(!cur->second->unbounded())

View File

@ -39,6 +39,8 @@
# include "package.h"
# include "vsignal.h"
# include "vtype.h"
# include "std_funcs.h"
# include "std_types.h"
# include <cstdarg>
# include <cstring>
# include <list>
@ -83,7 +85,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;
static SubprogramHeader*active_sub = NULL;
// perm_strings for attributes
const static perm_string left_attr = perm_string::literal("left");
@ -146,6 +148,7 @@ void parser_cleanup(void)
{
delete_design_entities();
delete_global_scope();
delete_std_funcs();
lex_strings.cleanup();
}
@ -228,8 +231,8 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
IfSequential::Elsif*elsif;
std::list<IfSequential::Elsif*>*elsif_list;
ExpConditional::else_t*exp_else;
std::list<ExpConditional::else_t*>*exp_else_list;
ExpConditional::case_t*exp_options;
std::list<ExpConditional::case_t*>*exp_options_list;
CaseSeqStmt::CaseStmtAlternative* case_alt;
std::list<CaseSeqStmt::CaseStmtAlternative*>* case_alt_list;
@ -262,7 +265,7 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
ReportStmt::severity_t severity;
Subprogram*subprogram;
SubprogramHeader*subprogram;
};
/* The keywords are all tokens. */
@ -308,6 +311,7 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
%type <interface_list> interface_element interface_list
%type <interface_list> port_clause port_clause_opt
%type <interface_list> generic_clause generic_clause_opt
%type <interface_list> parameter_list parameter_list_opt
%type <port_mode> mode mode_opt
%type <entity_aspect> entity_aspect entity_aspect_opt binding_indication binding_indication_semicolon_opt
@ -318,7 +322,7 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
%type <arch_statement> concurrent_conditional_signal_assignment
%type <arch_statement> concurrent_signal_assignment_statement concurrent_simple_signal_assignment
%type <arch_statement> for_generate_statement generate_statement if_generate_statement
%type <arch_statement> process_statement
%type <arch_statement> process_statement selected_signal_assignment
%type <arch_statement_list> architecture_statement_part generate_statement_body
%type <choice> choice
@ -331,8 +335,8 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
%type <expr> expression_logical_xnor expression_logical_xor
%type <expr> name prefix selected_name
%type <expr> shift_expression signal_declaration_assign_opt
%type <expr> simple_expression simple_expression_2 term waveform_element
%type <expr> interface_element_expression
%type <expr> simple_expression simple_expression_2 term
%type <expr> variable_declaration_assign_opt waveform_element interface_element_expression
%type <expr_list> waveform waveform_elements
%type <expr_list> name_list expression_list
@ -370,10 +374,12 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
%type <elsif> if_statement_elsif
%type <elsif_list> if_statement_elsif_list if_statement_elsif_list_opt
%type <exp_else> else_when_waveform
%type <exp_else_list> else_when_waveforms
%type <exp_options> else_when_waveform selected_waveform
%type <exp_options_list> else_when_waveforms selected_waveform_list
%type <subprogram> function_specification procedure_specification
%type <subprogram> subprogram_specification subprogram_body_start
%type <subprogram> function_specification subprogram_specification subprogram_body_start
%type <severity> severity severity_opt
%%
@ -800,12 +806,12 @@ concurrent_simple_signal_assignment
else_when_waveforms
: else_when_waveforms else_when_waveform
{ list<ExpConditional::else_t*>*tmp = $1;
{ list<ExpConditional::case_t*>*tmp = $1;
tmp ->push_back($2);
$$ = tmp;
}
| else_when_waveform
{ list<ExpConditional::else_t*>*tmp = new list<ExpConditional::else_t*>;
{ list<ExpConditional::case_t*>*tmp = new list<ExpConditional::case_t*>;
tmp->push_back($1);
$$ = tmp;
}
@ -813,12 +819,12 @@ else_when_waveforms
else_when_waveform
: K_else waveform K_when expression
{ ExpConditional::else_t*tmp = new ExpConditional::else_t($4, $2);
{ ExpConditional::case_t*tmp = new ExpConditional::case_t($4, $2);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| K_else waveform
{ ExpConditional::else_t*tmp = new ExpConditional::else_t(0, $2);
{ ExpConditional::case_t*tmp = new ExpConditional::case_t(0, $2);
FILE_NAME(tmp, @1);
$$ = tmp;
}
@ -827,11 +833,21 @@ else_when_waveform
concurrent_signal_assignment_statement /* IEEE 1076-2008 P11.6 */
: concurrent_simple_signal_assignment
| IDENTIFIER ':' concurrent_simple_signal_assignment { $$ = $3; }
| IDENTIFIER ':' concurrent_simple_signal_assignment
{ delete[] $1;
$$ = $3;
}
| concurrent_conditional_signal_assignment
| IDENTIFIER ':' concurrent_conditional_signal_assignment { $$ = $3; }
| IDENTIFIER ':' concurrent_conditional_signal_assignment
{ delete[] $1;
$$ = $3;
}
| selected_signal_assignment
| IDENTIFIER ':' selected_signal_assignment { $$ = $3; }
| name LEQ error ';'
{ errormsg(@2, "Syntax error in signal assignment waveform.\n");
@ -968,6 +984,7 @@ direction : K_to { $$ = false; } | K_downto { $$ = true; } ;
element_association
: choices ARROW expression
{ ExpAggregate::element_t*tmp = new ExpAggregate::element_t($1, $3);
delete $1;
$$ = tmp;
}
| expression
@ -991,7 +1008,9 @@ element_association_list
element_declaration
: identifier_list ':' subtype_indication ';'
{ $$ = record_elements($1, $3); }
{ $$ = record_elements($1, $3);
delete $1;
}
;
element_declaration_list
@ -1237,15 +1256,15 @@ for_generate_statement
;
function_specification /* IEEE 1076-2008 P4.2.1 */
: K_function IDENTIFIER '(' interface_list ')' K_return IDENTIFIER
{ perm_string type_name = lex_strings.make($7);
: K_function IDENTIFIER parameter_list K_return IDENTIFIER
{ perm_string type_name = lex_strings.make($5);
perm_string name = lex_strings.make($2);
const VType*type_mark = active_scope->find_type(type_name);
touchup_interface_for_functions($4);
Subprogram*tmp = new Subprogram(name, $4, type_mark);
FILE_NAME(tmp,@1);
touchup_interface_for_functions($3);
SubprogramHeader*tmp = new SubprogramHeader(name, $3, type_mark);
FILE_NAME(tmp, @1);
delete[]$2;
delete[]$7;
delete[]$5;
$$ = tmp;
}
;
@ -1267,8 +1286,8 @@ generic_clause_opt
;
generic_clause
: K_generic '(' interface_list ')' ';'
{ $$ = $3; }
: K_generic parameter_list ';'
{ $$ = $2; }
| K_generic '(' error ')' ';'
{ errormsg(@3, "Error in interface list for generic.\n");
yyerrok;
@ -1306,7 +1325,7 @@ identifier_list
}
;
identifier_opt : IDENTIFIER { $$ = $1; } | { $$ = 0; } ;
identifier_opt : IDENTIFIER { $$ = $1; } | { $$ = 0; } ;
identifier_colon_opt : IDENTIFIER ':' { $$ = $1; } | { $$ = 0; };
@ -1591,14 +1610,7 @@ mode_opt : mode {$$ = $1;} | {$$ = PORT_NONE;} ;
name /* IEEE 1076-2008 P8.1 */
: IDENTIFIER /* simple_name (IEEE 1076-2008 P8.2) */
{ Expression*tmp;
if(!strcasecmp($1, "true"))
tmp = new ExpBitstring("1");
else if(!strcasecmp($1, "false"))
tmp = new ExpBitstring("0");
else
tmp = new ExpName(lex_strings.make($1));
{ Expression*tmp = new ExpName(lex_strings.make($1));
FILE_NAME(tmp, @1);
delete[]$1;
$$ = tmp;
@ -1764,9 +1776,18 @@ package_body_start
}
;
parameter_list
: '(' interface_list ')' { $$ = $2; }
;
parameter_list_opt
: parameter_list { $$ = $1; }
| { $$ = 0; }
;
port_clause
: K_port '(' interface_list ')' ';'
{ $$ = $3; }
: K_port parameter_list ';'
{ $$ = $2; }
| K_port '(' error ')' ';'
{ errormsg(@1, "Syntax error in port list.\n");
yyerrok;
@ -1872,6 +1893,7 @@ primary
VHDL syntax). */
| IDENTIFIER '(' association_list ')'
{ sorrymsg(@1, "Function calls not supported\n");
delete[] $1;
$$ = 0;
}
@ -1890,19 +1912,26 @@ primary_unit
;
procedure_call
: IDENTIFIER
: IDENTIFIER ';'
{
ProcedureCall* tmp = new ProcedureCall(lex_strings.make($1));
sorrymsg(@1, "Procedure calls are not supported.\n");
delete[] $1;
$$ = tmp;
}
| IDENTIFIER '(' association_list ')'
| IDENTIFIER '(' association_list ')' ';'
{
ProcedureCall* tmp = new ProcedureCall(lex_strings.make($1), $3);
sorrymsg(@1, "Procedure calls are not supported.\n");
delete[] $1;
$$ = tmp;
}
| IDENTIFIER '(' error ')'
| IDENTIFIER '(' expression_list ')' ';'
{
ProcedureCall* tmp = new ProcedureCall(lex_strings.make($1), $3);
delete[] $1;
delete $3; // parameters are copied in this variant
$$ = tmp;
}
| IDENTIFIER '(' error ')' ';'
{ errormsg(@1, "Errors in procedure call.\n");
yyerrok;
delete[]$1;
@ -1911,10 +1940,24 @@ procedure_call
;
procedure_call_statement
: IDENTIFIER ':' procedure_call { $$ = $3; }
: IDENTIFIER ':' procedure_call
{ delete[] $1;
$$ = $3;
}
| procedure_call { $$ = $1; }
;
procedure_specification /* IEEE 1076-2008 P4.2.1 */
: K_procedure IDENTIFIER parameter_list_opt
{ perm_string name = lex_strings.make($2);
touchup_interface_for_functions($3);
SubprogramHeader*tmp = new SubprogramHeader(name, $3, NULL);
FILE_NAME(tmp, @1);
delete[]$2;
$$ = tmp;
}
;
process_declarative_item
: variable_declaration
;
@ -2175,6 +2218,47 @@ selected_names_lib
| selected_name_lib
;
selected_signal_assignment
: K_with expression K_select name LEQ selected_waveform_list ';'
{ ExpSelected*tmp = new ExpSelected($2, $6);
FILE_NAME(tmp, @3);
delete $2;
delete $6;
ExpName*name = dynamic_cast<ExpName*>($4);
assert(name);
SignalAssignment*tmpa = new SignalAssignment(name, tmp);
FILE_NAME(tmpa, @1);
$$ = tmpa;
}
;
selected_waveform
: waveform K_when expression
{ ExpConditional::case_t*tmp = new ExpConditional::case_t($3, $1);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| waveform K_when K_others
{ ExpConditional::case_t*tmp = new ExpConditional::case_t(0, $1);
FILE_NAME(tmp, @1);
$$ = tmp;
}
;
selected_waveform_list
: selected_waveform_list ',' selected_waveform
{ list<ExpConditional::case_t*>*tmp = $1;
tmp->push_back($3);
$$ = tmp;
}
| selected_waveform
{ list<ExpConditional::case_t*>*tmp = new list<ExpConditional::case_t*>;
tmp->push_back($1);
$$ = tmp;
}
;
sequence_of_statements
: sequence_of_statements sequential_statement
@ -2224,6 +2308,7 @@ severity
errormsg(@1, "Invalid severity level (possible values: NOTE, WARNING, ERROR, FAILURE).\n");
$$ = ReportStmt::UNSPECIFIED;
}
delete[] $2;
}
severity_opt
@ -2359,7 +2444,10 @@ signal_assignment
signal_assignment_statement
: signal_assignment
| IDENTIFIER ':' signal_assignment { $$ = $3; }
| IDENTIFIER ':' signal_assignment
{ delete[] $1;
$$ = $3;
}
subprogram_body_start
: subprogram_specification K_is
@ -2375,16 +2463,20 @@ subprogram_body /* IEEE 1076-2008 P4.3 */
: subprogram_body_start subprogram_declarative_part
K_begin subprogram_statement_part K_end
subprogram_kind_opt identifier_opt ';'
{ Subprogram*prog = $1;
Subprogram*tmp = active_scope->recall_subprogram(prog->name());
{ SubprogramHeader*prog = $1;
SubprogramHeader*tmp = active_scope->recall_subprogram(prog->name());
if (tmp && prog->compare_specification(tmp)) {
delete prog;
prog = tmp;
} else if (tmp) {
errormsg(@1, "Subprogram specification for %s doesn't match specification in package header.\n", prog->name().str());
}
prog->transfer_from(*active_scope, ScopeBase::VARIABLES);
prog->set_program_body($4);
SubprogramBody*body = new SubprogramBody();
body->transfer_from(*active_scope, ScopeBase::VARIABLES);
body->set_statements($4);
prog->set_body(body);
active_scope->bind_name(prog->name(), prog);
active_sub = NULL;
}
@ -2429,6 +2521,7 @@ subprogram_kind_opt : subprogram_kind | ;
subprogram_specification
: function_specification { $$ = $1; }
| procedure_specification { $$ = $1; }
;
/* This is an implementation of the rule:
@ -2444,6 +2537,7 @@ subprogram_statement_part
subtype_declaration
: K_subtype IDENTIFIER K_is subtype_indication ';'
{ perm_string name = lex_strings.make($2);
delete[] $2;
if ($4 == 0) {
errormsg(@1, "Failed to declare type name %s.\n", name.str());
} else {
@ -2593,7 +2687,10 @@ use_clauses_opt
variable_assignment_statement /* IEEE 1076-2008 P10.6.1 */
: variable_assignment
| IDENTIFIER ':' variable_assignment { $$ = $3; }
| IDENTIFIER ':' variable_assignment
{ delete[] $1;
$$ = $3;
}
variable_assignment
: name VASSIGN expression ';'
@ -2616,11 +2713,12 @@ variable_assignment
;
variable_declaration /* IEEE 1076-2008 P6.4.2.4 */
: K_shared_opt K_variable identifier_list ':' subtype_indication ';'
: K_shared_opt K_variable identifier_list ':' subtype_indication
variable_declaration_assign_opt ';'
{ /* 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);
Variable*sig = new Variable(*cur, $5, $6);
FILE_NAME(sig, @2);
active_scope->bind_name(*cur, sig);
}
@ -2632,6 +2730,11 @@ variable_declaration /* IEEE 1076-2008 P6.4.2.4 */
}
;
variable_declaration_assign_opt
: VASSIGN expression { $$ = $2; }
| { $$ = 0; }
;
wait_statement
: K_wait K_for expression ';'
{ WaitForStmt*tmp = new WaitForStmt($3);

View File

@ -63,8 +63,4 @@ extern void library_import(const YYLTYPE&loc, const std::list<perm_string>*names
extern void library_use(const YYLTYPE&loc, ActiveScope*res, const char*libname, const char*pack, const char*ident);
extern void generate_global_types(ActiveScope*res);
extern bool is_global_type(perm_string type_name);
#endif /* IVL_parse_misc_H */

View File

@ -22,6 +22,8 @@
# include "package.h"
# include "subprogram.h"
# include "entity.h"
# include "std_funcs.h"
# include "std_types.h"
# include <algorithm>
# include <iostream>
# include <iterator>
@ -65,9 +67,9 @@ ScopeBase::ScopeBase(const ActiveScope&ref)
// an active scope and is making the actual scope. At this point
// we know that "this" is the parent scope for the subprograms,
// so set it now.
for (map<perm_string,Subprogram*>::iterator cur = cur_subprograms_.begin()
; cur != cur_subprograms_.end() ; ++ cur) {
cur->second->set_parent(this);
for (map<perm_string,SubprogramHeader*>::iterator cur = cur_subprograms_.begin()
; cur != cur_subprograms_.end(); ++cur) {
cur->second->set_parent(this);
}
}
@ -156,15 +158,20 @@ Variable* ScopeBase::find_variable(perm_string by_name) const
}
}
const InterfacePort* ScopeBase::find_param(perm_string by_name) const
const InterfacePort* ScopeBase::find_param(perm_string) const
{
for(map<perm_string,Subprogram*>::const_iterator it = use_subprograms_.begin();
return NULL;
}
const InterfacePort* ScopeBase::find_param_all(perm_string by_name) const
{
for(map<perm_string,SubprogramHeader*>::const_iterator it = use_subprograms_.begin();
it != use_subprograms_.end(); ++it) {
if(const InterfacePort*port = it->second->find_param(by_name))
return port;
}
for(map<perm_string,Subprogram*>::const_iterator it = cur_subprograms_.begin();
for(map<perm_string,SubprogramHeader*>::const_iterator it = cur_subprograms_.begin();
it != cur_subprograms_.end(); ++it) {
if(const InterfacePort*port = it->second->find_param(by_name))
return port;
@ -173,9 +180,9 @@ const InterfacePort* ScopeBase::find_param(perm_string by_name) const
return NULL;
}
Subprogram* ScopeBase::find_subprogram(perm_string name) const
SubprogramHeader* ScopeBase::find_subprogram(perm_string name) const
{
map<perm_string,Subprogram*>::const_iterator cur;
map<perm_string,SubprogramHeader*>::const_iterator cur;
cur = cur_subprograms_.find(name);
if (cur != cur_subprograms_.end())
@ -185,7 +192,7 @@ Subprogram* 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
@ -196,7 +203,7 @@ const VTypeEnum* ScopeBase::is_enum_name(perm_string name) const
return *it;
}
return NULL;
return find_std_enum_name(name);
}
/*
@ -218,7 +225,7 @@ void ScopeBase::do_use_from(const ScopeBase*that)
old_components_[cur->first] = cur->second;
}
for (map<perm_string,Subprogram*>::const_iterator cur = that->cur_subprograms_.begin()
for (map<perm_string,SubprogramHeader*>::const_iterator cur = that->cur_subprograms_.begin()
; cur != that->cur_subprograms_.end() ; ++ cur) {
if (cur->second == 0)
continue;
@ -274,9 +281,9 @@ void ActiveScope::set_package_header(Package*pkg)
package_header_ = pkg;
}
Subprogram* ActiveScope::recall_subprogram(perm_string name) const
SubprogramHeader* ActiveScope::recall_subprogram(perm_string name) const
{
if (Subprogram*tmp = find_subprogram(name))
if (SubprogramHeader*tmp = find_subprogram(name))
return tmp;
if (package_header_)

View File

@ -32,7 +32,7 @@ class ActiveScope;
class Architecture;
class ComponentBase;
class Package;
class Subprogram;
class SubprogramHeader;
class VType;
template<typename T>
@ -57,7 +57,8 @@ class ScopeBase {
Signal* find_signal(perm_string by_name) const;
Variable* find_variable(perm_string by_name) const;
virtual const InterfacePort* find_param(perm_string by_name) const;
Subprogram* find_subprogram(perm_string by_name) const;
const InterfacePort* find_param_all(perm_string by_name) const;
SubprogramHeader* find_subprogram(perm_string by_name) const;
// Checks if a string is one of possible enum values. If so, the enum
// type is returned, otherwise NULL.
const VTypeEnum* is_enum_name(perm_string name) const;
@ -67,8 +68,8 @@ class ScopeBase {
enum transfer_type_t { SIGNALS = 1, VARIABLES = 2, COMPONENTS = 4, ALL = 0xffff };
void transfer_from(ScopeBase&ref, transfer_type_t what = ALL);
inline void bind_subprogram(perm_string name, Subprogram*obj)
{ map<perm_string, Subprogram*>::iterator it;
inline void bind_subprogram(perm_string name, SubprogramHeader*obj)
{ map<perm_string, SubprogramHeader*>::iterator it;
if((it = use_subprograms_.find(name)) != use_subprograms_.end() )
use_subprograms_.erase(it);
cur_subprograms_[name] = obj;
@ -116,8 +117,8 @@ class ScopeBase {
std::map<perm_string, struct const_t*> use_constants_; //imported constants
std::map<perm_string, struct const_t*> cur_constants_; //current constants
std::map<perm_string, Subprogram*> use_subprograms_; //imported
std::map<perm_string, Subprogram*> cur_subprograms_; //current
std::map<perm_string, SubprogramHeader*> use_subprograms_; //imported
std::map<perm_string, SubprogramHeader*> cur_subprograms_; //current
std::list<const VTypeEnum*> use_enums_;
@ -170,7 +171,7 @@ class ActiveScope : public ScopeBase {
// Locate the subprogram by name. The subprogram body uses
// this to locate the sobprogram declaration. Note that the
// subprogram may be in a package header.
Subprogram* recall_subprogram(perm_string name) const;
SubprogramHeader* recall_subprogram(perm_string name) const;
/* All bind_name function check if the given name was present
* in previous scopes. If it is found, it is erased (but the pointer
@ -219,8 +220,8 @@ class ActiveScope : public ScopeBase {
cur_constants_[name] = new const_t(obj, val);
}
inline void bind_name(perm_string name, Subprogram*obj)
{ map<perm_string, Subprogram*>::iterator it;
inline void bind_name(perm_string name, SubprogramHeader*obj)
{ map<perm_string, SubprogramHeader*>::iterator it;
if((it = use_subprograms_.find(name)) != use_subprograms_.end() )
use_subprograms_.erase(it);
cur_subprograms_[name] = obj;

View File

@ -169,17 +169,31 @@ void CaseSeqStmt::CaseStmtAlternative::visit(SeqStmtVisitor& func)
}
ProcedureCall::ProcedureCall(perm_string name)
: name_(name), param_list_(0)
: name_(name), param_list_(NULL), def_(NULL)
{
}
ProcedureCall::ProcedureCall(perm_string name, std::list<named_expr_t*>* param_list)
: name_(name), param_list_(param_list)
: name_(name), param_list_(param_list), def_(NULL)
{
}
ProcedureCall::ProcedureCall(perm_string name, std::list<Expression*>* param_list)
: name_(name), def_(NULL)
{
param_list_ = new std::list<named_expr_t*>;
for(std::list<Expression*>::const_iterator it = param_list->begin();
it != param_list->end(); ++it)
{
param_list_->push_back(new named_expr_t(empty_perm_string, (*it)->clone()));
}
}
ProcedureCall::~ProcedureCall()
{
if(!param_list_)
return;
while(param_list_->size() > 0) {
named_expr_t* cur = param_list_->front();
param_list_->pop_front();

View File

@ -203,6 +203,7 @@ class ProcedureCall : public SequentialStmt {
public:
ProcedureCall(perm_string name);
ProcedureCall(perm_string name, std::list<named_expr_t*>* param_list);
ProcedureCall(perm_string name, std::list<Expression*>* param_list);
~ProcedureCall();
int elaborate(Entity*ent, ScopeBase*scope);
@ -212,6 +213,7 @@ class ProcedureCall : public SequentialStmt {
private:
perm_string name_;
std::list<named_expr_t*>* param_list_;
SubprogramHeader*def_;
};
class VariableSeqAssignment : public SequentialStmt {

View File

@ -20,6 +20,8 @@
# include "sequential.h"
# include "expression.h"
# include "scope.h"
# include "library.h"
# include "subprogram.h"
int SequentialStmt::elaborate(Entity*, ScopeBase*)
{
@ -149,16 +151,39 @@ 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);
}
return errors;
}
int ProcedureCall::elaborate(Entity*, ScopeBase*)
int ProcedureCall::elaborate(Entity*ent, ScopeBase*scope)
{
return 0;
int errors = 0;
def_ = scope->find_subprogram(name_);
if(!def_)
def_ = library_find_subprogram(name_);
assert(def_);
// Elaborate arguments
size_t idx = 0;
if(param_list_) {
for(list<named_expr_t*>::iterator cur = param_list_->begin()
; cur != param_list_->end() ; ++cur) {
const VType*tmp = (*cur)->expr()->probe_type(ent, scope);
const VType*param_type = def_ ? def_->peek_param_type(idx) : NULL;
if(!tmp && param_type)
tmp = param_type;
errors += (*cur)->expr()->elaborate_expr(ent, scope, tmp);
}
}
return errors;
}
int VariableSeqAssignment::elaborate(Entity*ent, ScopeBase*scope)

View File

@ -23,7 +23,9 @@
# include "sequential.h"
# include "expression.h"
# include "architec.h"
# include "package.h"
# include "compiler.h"
# include "subprogram.h"
# include <iostream>
# include <cstdio>
# include <typeinfo>
@ -205,12 +207,29 @@ void VariableSeqAssignment::write_to_stream(ostream&fd)
fd << ";" << endl;
}
int ProcedureCall::emit(ostream&out, Entity*, ScopeBase*)
int ProcedureCall::emit(ostream&out, Entity*ent, ScopeBase*scope)
{
out << " // " << get_fileline() << ": internal error: "
<< "I don't know how to emit this sequential statement! "
<< "type=" << typeid(*this).name() << endl;
return 1;
int errors = 0;
std::vector<Expression*>params(param_list_->size());
int i = 0;
for(std::list<named_expr_t*>::iterator it = param_list_->begin();
it != param_list_->end(); ++it)
params[i++] = (*it)->expr();
const Package*pkg = dynamic_cast<const Package*> (def_->get_parent());
if (pkg != 0)
out << "\\" << pkg->name() << " ::";
errors += def_->emit_name(params, out, ent, scope);
out << " (";
if(param_list_) {
errors += def_->emit_args(params, out, ent, scope);
}
out << ");" << endl;
return errors;
}
int LoopStatement::emit_substatements(ostream&out, Entity*ent, ScopeBase*scope)

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 "std_types.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, &type_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, &type_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 */

119
vhdlpp/std_types.cc Normal file
View File

@ -0,0 +1,119 @@
/*
* 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_types.h"
#include "scope.h"
static std::map<perm_string, VTypeDef*> std_types;
// this list contains enums used by typedefs in the std_types map
static std::list<const VTypeEnum*> std_enums;
const VTypePrimitive primitive_BIT(VTypePrimitive::BIT, true);
const VTypePrimitive primitive_INTEGER(VTypePrimitive::INTEGER);
const VTypePrimitive primitive_NATURAL(VTypePrimitive::NATURAL);
const VTypePrimitive primitive_REAL(VTypePrimitive::REAL);
const VTypePrimitive primitive_STDLOGIC(VTypePrimitive::STDLOGIC, true);
const VTypePrimitive primitive_CHARACTER(VTypePrimitive::CHARACTER);
const VTypePrimitive primitive_TIME(VTypePrimitive::TIME);
VTypeDef type_BOOLEAN(perm_string::literal("boolean"));
const VTypeArray primitive_BIT_VECTOR(&primitive_BIT, vector<VTypeArray::range_t> (1));
const VTypeArray primitive_BOOL_VECTOR(&type_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));
const VTypeArray primitive_SIGNED(&primitive_STDLOGIC, vector<VTypeArray::range_t> (1), true);
const VTypeArray primitive_UNSIGNED(&primitive_STDLOGIC, vector<VTypeArray::range_t> (1), false);
void generate_global_types(ActiveScope*res)
{
// boolean
std::list<perm_string>*enum_BOOLEAN_vals = new std::list<perm_string>;
enum_BOOLEAN_vals->push_back(perm_string::literal("false"));
enum_BOOLEAN_vals->push_back(perm_string::literal("true"));
VTypeEnum*enum_BOOLEAN = new VTypeEnum(enum_BOOLEAN_vals);
type_BOOLEAN.set_definition(enum_BOOLEAN);
std_types[type_BOOLEAN.peek_name()] = &type_BOOLEAN;
std_enums.push_back(enum_BOOLEAN);
res->use_name(type_BOOLEAN.peek_name(), &type_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 delete_global_types()
{
typedef_context_t typedef_ctx;
for(map<perm_string, VTypeDef*>::iterator cur = std_types.begin();
cur != std_types.end() ; ++ cur) {
delete cur->second->peek_definition();
delete cur->second;
}
}
const VTypeEnum*find_std_enum_name(perm_string name)
{
for(list<const VTypeEnum*>::const_iterator it = std_enums.begin();
it != std_enums.end(); ++it) {
if((*it)->has_name(name))
return *it;
}
return NULL;
}
void emit_std_types(ostream&fd)
{
fd << "`ifndef __VHDL_STD_TYPES" << endl;
fd << "`define __VHDL_STD_TYPES" << endl;
typedef_context_t typedef_ctx;
for(map<perm_string, VTypeDef*>::iterator cur = std_types.begin();
cur != std_types.end() ; ++ cur) {
cur->second->emit_typedef(fd, typedef_ctx);
}
fd << "`endif" << endl;
}
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 == "string") return true;
if (name == "natural") return true;
if (name == "signed") return true;
if (name == "unsigned") return true;
if (name == "time") return true;
return std_types.count(name) > 0;
}

48
vhdlpp/std_types.h Normal file
View File

@ -0,0 +1,48 @@
/*
* 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 "vtype.h"
class ActiveScope;
void emit_std_types(ostream&out);
int emit_packages(void);
void generate_global_types(ActiveScope*res);
bool is_global_type(perm_string type_name);
void delete_global_types();
const VTypeEnum*find_std_enum_name(perm_string name);
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 VTypeDef type_BOOLEAN;
extern const VTypeArray primitive_BIT_VECTOR;
extern const VTypeArray primitive_BOOL_VECTOR;
extern const VTypeArray primitive_STDLOGIC_VECTOR;
extern const VTypeArray primitive_STRING;
extern const VTypeArray primitive_SIGNED;
extern const VTypeArray primitive_UNSIGNED;

View File

@ -30,44 +30,70 @@
using namespace std;
Subprogram::Subprogram(perm_string nam, list<InterfacePort*>*ports,
const VType*return_type)
: name_(nam), parent_(0), ports_(ports), return_type_(return_type), statements_(0)
SubprogramBody::SubprogramBody()
: statements_(NULL), header_(NULL)
{
}
Subprogram::~Subprogram()
SubprogramBody::~SubprogramBody()
{
}
void Subprogram::set_parent(const ScopeBase*par)
const InterfacePort*SubprogramBody::find_param(perm_string nam) const
{
ivl_assert(*this, parent_ == 0);
parent_ = par;
if(!header_)
return NULL;
return header_->find_param(nam);
}
void Subprogram::set_program_body(list<SequentialStmt*>*stmt)
void SubprogramBody::set_statements(list<SequentialStmt*>*stmt)
{
ivl_assert(*this, statements_==0);
statements_ = stmt;
}
bool Subprogram::unbounded() const {
if(return_type_->is_unbounded())
return true;
void SubprogramBody::write_to_stream(ostream&fd) const
{
for (map<perm_string,Variable*>::const_iterator cur = new_variables_.begin()
; cur != new_variables_.end() ; ++cur) {
cur->second->write_to_stream(fd);
}
if(ports_) {
for(std::list<InterfacePort*>::const_iterator it = ports_->begin();
it != ports_->end(); ++it) {
if((*it)->type->is_unbounded())
return true;
}
}
fd << "begin" << endl;
return false;
if (statements_) {
for (list<SequentialStmt*>::const_iterator cur = statements_->begin()
; cur != statements_->end() ; ++cur) {
(*cur)->write_to_stream(fd);
}
} else {
fd << "--empty body" << endl;
}
fd << "end function;" << endl;
}
bool Subprogram::compare_specification(Subprogram*that) const
SubprogramHeader::SubprogramHeader(perm_string nam, list<InterfacePort*>*ports,
const VType*return_type)
: name_(nam), ports_(ports), return_type_(return_type), body_(NULL), parent_(NULL)
{
}
SubprogramHeader::~SubprogramHeader()
{
delete body_;
if(ports_) {
for(list<InterfacePort*>::iterator it = ports_->begin();
it != ports_->end(); ++it)
{
delete *it;
}
delete ports_;
}
}
bool SubprogramHeader::compare_specification(SubprogramHeader*that) const
{
if (name_ != that->name_)
return false;
@ -98,7 +124,7 @@ bool Subprogram::compare_specification(Subprogram*that) const
return true;
}
const InterfacePort*Subprogram::find_param(perm_string nam) const
const InterfacePort*SubprogramHeader::find_param(perm_string nam) const
{
if(!ports_)
return NULL;
@ -112,7 +138,7 @@ const InterfacePort*Subprogram::find_param(perm_string nam) const
return NULL;
}
const VType*Subprogram::peek_param_type(int idx) const
const VType*SubprogramHeader::peek_param_type(int idx) const
{
if(!ports_ || idx < 0 || (size_t)idx >= ports_->size())
return NULL;
@ -123,7 +149,37 @@ const VType*Subprogram::peek_param_type(int idx) const
return (*p)->type;
}
Subprogram*Subprogram::make_instance(std::vector<Expression*> arguments, ScopeBase*scope) {
void SubprogramHeader::set_parent(const ScopeBase*par)
{
ivl_assert(*this, !parent_);
parent_ = par;
}
bool SubprogramHeader::unbounded() const {
if(return_type_ && return_type_->is_unbounded())
return true;
if(ports_) {
for(std::list<InterfacePort*>::const_iterator it = ports_->begin();
it != ports_->end(); ++it) {
if((*it)->type->is_unbounded())
return true;
}
}
return false;
}
void SubprogramHeader::set_body(SubprogramBody*bdy)
{
ivl_assert(*this, !body_);
body_ = bdy;
ivl_assert(*this, !bdy->header_);
bdy->header_ = this;
}
SubprogramHeader*SubprogramHeader::make_instance(std::vector<Expression*> arguments,
ScopeBase*scope) const {
assert(arguments.size() == ports_->size());
std::list<InterfacePort*>*ports = new std::list<InterfacePort*>;
@ -142,25 +198,31 @@ Subprogram*Subprogram::make_instance(std::vector<Expression*> arguments, ScopeBa
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_);
SubprogramHeader*instance = new SubprogramHeader(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;
if(body_) {
SubprogramBody*body_inst = new SubprogramBody();
// Copy variables
for(std::map<perm_string,Variable*>::iterator it = body_->new_variables_.begin();
it != body_->new_variables_.end(); ++it) {
Variable*v = new Variable(it->first, it->second->peek_type()->clone());
body_inst->new_variables_[it->first] = v;
}
body_inst->set_statements(body_->statements_);
instance->set_parent(scope);
instance->set_body(body_inst);
instance->fix_return_type();
}
instance->set_parent(scope);
instance->set_program_body(statements_);
instance->fix_return_type();
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) {}
check_return_type(const SubprogramBody*subp) : subp_(subp), ret_type_(NULL) {}
void operator() (SequentialStmt*s)
{
@ -195,38 +257,44 @@ struct check_return_type : public SeqStmtVisitor {
const VType*get_type() const { return ret_type_; }
private:
const Subprogram*subp_;
const SubprogramBody*subp_;
const VType*ret_type_;
};
void Subprogram::fix_return_type()
void SubprogramHeader::fix_return_type()
{
if(!statements_)
if(!body_ || !body_->statements_)
return;
check_return_type r(this);
check_return_type r(body_);
for (std::list<SequentialStmt*>::iterator s = statements_->begin()
; s != statements_->end(); ++s) {
for (std::list<SequentialStmt*>::iterator s = body_->statements_->begin()
; s != body_->statements_->end(); ++s) {
(*s)->visit(r);
}
VType*return_type = const_cast<VType*>(r.get_type());
if(return_type && !return_type->is_unbounded()) {
// Let's check if the variable length can be evaluated without any scope.
// If not, then it is depends on information about e.g. function params
// If not, then it depends on information about e.g. function params
if(return_type->is_variable_length(NULL)) {
if(VTypeArray*arr = dynamic_cast<VTypeArray*>(return_type))
arr->evaluate_ranges(this);
arr->evaluate_ranges(body_);
}
return_type_ = return_type;
}
}
void Subprogram::write_to_stream(ostream&fd) const
void SubprogramHeader::write_to_stream(ostream&fd) const
{
fd << " function " << name_ << "(";
if(return_type_)
fd << "function ";
else
fd << "procedure ";
fd << name_;
if (ports_ && ! ports_->empty()) {
fd << "(";
list<InterfacePort*>::const_iterator cur = ports_->begin();
InterfacePort*curp = *cur;
fd << curp->name << " : ";
@ -236,44 +304,21 @@ void Subprogram::write_to_stream(ostream&fd) const
fd << "; " << curp->name << " : ";
curp->type->write_to_stream(fd);
}
fd << ")";
}
if( return_type_) {
fd << " return ";
return_type_->write_to_stream(fd);
}
fd << ") return ";
return_type_->write_to_stream(fd);
fd << ";" << endl;
}
void Subprogram::write_to_stream_body(ostream&fd) const
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()
{
fd << "function " << name_ << "(";
if (ports_ && ! ports_->empty()) {
list<InterfacePort*>::const_iterator cur = ports_->begin();
InterfacePort*curp = *cur;
fd << curp->name << " : ";
curp->type->write_to_stream(fd);
for (++cur ; cur != ports_->end() ; ++cur) {
curp = *cur;
fd << "; " << curp->name << " : ";
curp->type->write_to_stream(fd);
}
}
fd << ") return ";
return_type_->write_to_stream(fd);
fd << " is" << endl;
for (map<perm_string,Variable*>::const_iterator cur = new_variables_.begin()
; cur != new_variables_.end() ; ++cur) {
cur->second->write_to_stream(fd);
}
fd << "begin" << endl;
if (statements_) {
for (list<SequentialStmt*>::const_iterator cur = statements_->begin()
; cur != statements_->end() ; ++cur) {
(*cur)->write_to_stream(fd);
}
} else {
fd << "--empty body" << endl;
}
fd << "end function;" << endl;
}

View File

@ -27,63 +27,122 @@
# include "scope.h"
# include <iostream>
# include <list>
# include <cassert>
class InterfacePort;
class SequentialStmt;
class VType;
class SubprogramHeader;
class Subprogram : public LineInfo, public ScopeBase {
class SubprogramBody : public LineInfo, public ScopeBase {
public:
Subprogram(perm_string name, std::list<InterfacePort*>*ports,
SubprogramBody();
~SubprogramBody();
const InterfacePort*find_param(perm_string nam) const;
void set_statements(std::list<SequentialStmt*>*statements);
inline bool empty_statements() const { return !statements_ || statements_->empty(); }
int emit(ostream&out, Entity*ent, ScopeBase*scope);
// Emit body as it would show up in a package.
int emit_package(std::ostream&fd) const;
void write_to_stream(std::ostream&fd) const;
void dump(std::ostream&fd) const;
private:
std::list<SequentialStmt*>*statements_;
SubprogramHeader*header_;
friend class SubprogramHeader;
};
class SubprogramHeader : public LineInfo {
public:
SubprogramHeader(perm_string name, std::list<InterfacePort*>*ports,
const VType*return_type);
~Subprogram();
void set_parent(const ScopeBase*par);
inline const ScopeBase*get_parent() const { return parent_; }
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(); }
virtual ~SubprogramHeader();
// Return true if the specification (name, types, ports)
// matches this subprogram and that subprogram.
bool compare_specification(Subprogram*that) const;
bool compare_specification(SubprogramHeader*that) const;
const InterfacePort*find_param(perm_string nam) const;
const VType*peek_param_type(int idx) const;
const VType*peek_return_type() const { return return_type_; }
int emit(ostream&out, Entity*ent, ScopeBase*scope);
void set_parent(const ScopeBase*par);
inline const ScopeBase*get_parent() const { return parent_; }
// Emit a definition as it would show up in a package.
int emit_package(std::ostream&fd) const;
// Checks if either return type or parameters are unbounded vectors.
bool unbounded() const;
void write_to_stream(std::ostream&fd) const;
void write_to_stream_body(std::ostream&fd) const;
void dump(std::ostream&fd) const;
// 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() 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.
Subprogram*make_instance(std::vector<Expression*> arguments, ScopeBase*scope);
SubprogramHeader*make_instance(std::vector<Expression*> arguments, ScopeBase*scope) const;
// Checks if either return type or parameters are unbounded vectors.
bool unbounded() const;
// Emit header as it would show up in a package.
int emit_package(std::ostream&fd) const;
private:
void write_to_stream(std::ostream&fd) const;
void dump(std::ostream&fd) const;
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.
void fix_return_type();
// Procedure/function name
perm_string name_;
const ScopeBase*parent_;
std::list<InterfacePort*>*ports_;
const VType*return_type_;
std::list<SequentialStmt*>*statements_;
SubprogramBody*body_;
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

@ -25,19 +25,42 @@
using namespace std;
int Subprogram::emit_package(ostream&fd) const
int SubprogramBody::emit_package(ostream&fd) const
{
int errors = 0;
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) {
errors += (*cur)->emit(fd, NULL, const_cast<SubprogramBody*>(this));
}
} else {
fd << " begin /* empty body */ end" << endl;
}
return errors;
}
int SubprogramHeader::emit_package(ostream&fd) const
{
int errors = 0;
if (return_type_) {
fd << "function ";
return_type_->emit_def(fd, empty_perm_string);
fd << " " << name_;
fd << "(";
} else {
fd << "task " << name_ << ";" << endl;
fd << "task";
}
fd << " \\" << name_ << " (";
for (list<InterfacePort*>::const_iterator cur = ports_->begin()
; cur != ports_->end() ; ++cur) {
if (cur != ports_->begin())
@ -63,21 +86,8 @@ 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) {
errors += (*cur)->emit(fd, NULL, const_cast<Subprogram*>(this));
}
} else {
fd << " begin /* empty body */ end" << endl;
}
if (body_)
body_->emit_package(fd);
if (return_type_)
fd << "endfunction" << endl;
@ -86,3 +96,31 @@ int Subprogram::emit_package(ostream&fd) const
return errors;
}
int SubprogramHeader::emit_name(const std::vector<Expression*>&,
std::ostream&out, Entity*, ScopeBase*) const
{
out << "\\" << name_;
return 0;
}
int SubprogramHeader::emit_args(const std::vector<Expression*>&argv,
std::ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
for (size_t idx = 0; idx < argv.size() ; idx += 1) {
if (idx > 0) out << ", ";
errors += argv[idx]->emit(out, ent, scope);
}
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

@ -66,7 +66,7 @@ int Signal::emit(ostream&out, Entity*ent, ScopeBase*scope)
return errors;
}
int Variable::emit(ostream&out, Entity*, ScopeBase*)
int Variable::emit(ostream&out, Entity*ent, ScopeBase*scope)
{
int errors = 0;
@ -75,6 +75,12 @@ int Variable::emit(ostream&out, Entity*, ScopeBase*)
if (peek_refcnt_sequ_() > 0 || !peek_type()->can_be_packed())
decl.reg_flag = true;
errors += decl.emit(out, peek_name());
Expression*init_expr = peek_init_expr();
if (init_expr) {
out << " = ";
init_expr->emit(out, ent, scope);
}
out << ";" << endl;
return errors;
}

View File

@ -77,7 +77,7 @@ class Signal : public SigVarBase {
class Variable : public SigVarBase {
public:
Variable(perm_string name, const VType*type);
Variable(perm_string name, const VType*type, Expression*init_expr = NULL);
int emit(ostream&out, Entity*ent, ScopeBase*scope);
void write_to_stream(std::ostream&fd);
@ -93,8 +93,8 @@ inline Signal::Signal(perm_string name, const VType*type, Expression*init_expr)
{
}
inline Variable::Variable(perm_string name, const VType*type)
: SigVarBase(name, type, 0)
inline Variable::Variable(perm_string name, const VType*type, Expression*init_expr)
: SigVarBase(name, type, init_expr)
{
}

View File

@ -55,9 +55,6 @@ VTypePrimitive::~VTypePrimitive()
void VTypePrimitive::show(ostream&out) const
{
switch (type_) {
case BOOLEAN:
out << "BOOLEAN";
break;
case BIT:
out << "BIT";
break;
@ -85,7 +82,6 @@ void VTypePrimitive::show(ostream&out) const
int VTypePrimitive::get_width(ScopeBase*) const
{
switch(type_) {
case BOOLEAN:
case BIT:
case STDLOGIC:
return 1;
@ -266,12 +262,11 @@ bool VTypeArray::is_variable_length(ScopeBase*scope) const {
void VTypeArray::evaluate_ranges(ScopeBase*scope) {
for(std::vector<range_t>::iterator it = ranges_.begin(); it != ranges_.end(); ++it ) {
int64_t lsb_val = -1, msb_val = -1;
bool dir = it->is_downto();
if(it->msb()->evaluate(scope, msb_val) && it->lsb()->evaluate(scope, lsb_val)) {
assert(lsb_val >= 0);
assert(msb_val >= 0);
*it = range_t(new ExpInteger(msb_val), new ExpInteger(lsb_val), dir);
*it = range_t(new ExpInteger(msb_val), new ExpInteger(lsb_val), msb_val > lsb_val);
}
}
}

View File

@ -156,7 +156,7 @@ class VTypeERROR : public VType {
class VTypePrimitive : public VType {
public:
enum type_t { BOOLEAN, BIT, INTEGER, NATURAL, REAL, STDLOGIC, CHARACTER, TIME };
enum type_t { BIT, INTEGER, NATURAL, REAL, STDLOGIC, CHARACTER, TIME };
public:
VTypePrimitive(type_t tt, bool packed = false);
@ -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
@ -265,6 +256,8 @@ class VTypeArray : public VType {
private:
int emit_with_dims_(std::ostream&out, bool packed, perm_string name) const;
// Handles a few special types of array (*_vector, string types).
bool write_special_case(std::ostream&out) const;
void write_range_to_stream_(std::ostream&fd) const;
const VType*etype_;
@ -363,6 +356,8 @@ class VTypeDef : public VType {
VType*clone() const { return new VTypeDef(*this); }
bool type_match(const VType*that) const;
inline perm_string peek_name() const { return name_; }
// If the type is not given a definition in the constructor,

View File

@ -132,7 +132,7 @@ int VTypeArray::emit_with_dims_(std::ostream&out, bool packed, perm_string name)
int VTypeEnum::emit_def(ostream&out, perm_string name) const
{
int errors = 0;
out << "enum {";
out << "enum integer {";
assert(names_.size() >= 1);
out << "\\" << names_[0] << " ";
for (size_t idx = 1 ; idx < names_.size() ; idx += 1)
@ -148,9 +148,6 @@ int VTypePrimitive::emit_primitive_type(ostream&out) const
{
int errors = 0;
switch (type_) {
case BOOLEAN:
out << "boolean";
break;
case BIT:
out << "bit";
break;
@ -167,7 +164,7 @@ int VTypePrimitive::emit_primitive_type(ostream&out) const
out << "real";
break;
case CHARACTER:
out << "char";
out << "byte";
break;
case TIME:
out << "time";
@ -229,10 +226,9 @@ int VTypeDef::emit_def(ostream&out, perm_string name) const
int VTypeDef::emit_decl(ostream&out, perm_string name, bool reg_flag) const
{
int errors = 0;
if (reg_flag)
out << "reg ";
else
out << "wire ";
if (!dynamic_cast<const VTypeEnum*>(type_))
out << (reg_flag ? "reg " : "wire ");
if(dynamic_cast<const VTypeArray*>(type_)) {
errors += type_->emit_def(out, name);

View File

@ -22,5 +22,21 @@
bool VType::type_match(const VType*that) const
{
return this == that;
if(this == that)
return true;
if(const VTypeDef*tdef = dynamic_cast<const VTypeDef*>(that)) {
if(type_match(tdef->peek_definition()))
return true;
}
return false;
}
bool VTypeDef::type_match(const VType*that) const
{
if(VType::type_match(that))
return true;
return VType::type_match(type_);
}

View File

@ -18,7 +18,7 @@
*/
# define __STDC_LIMIT_MACROS
# include "vtype.h"
# include "std_types.h"
# include "expression.h"
# include <typeinfo>
# include <stdint.h>
@ -38,20 +38,8 @@ void VType::write_type_to_stream(ostream&fd) const
void VTypeArray::write_to_stream(ostream&fd) const
{
// Special cases: std_logic_vector & string
if (etype_ == &primitive_STDLOGIC) {
fd << "std_logic_vector";
if (!ranges_.empty() && !ranges_[0].is_box()) {
write_range_to_stream_(fd);
}
return;
} else if (etype_ == &primitive_CHARACTER) {
fd << "string";
if (!ranges_.empty() && !ranges_[0].is_box()) {
write_range_to_stream_(fd);
}
return;
}
if(write_special_case(fd))
return;
bool typedefed = false;
if(const VTypeDef*tdef = dynamic_cast<const VTypeDef*>(etype_)) {
@ -96,26 +84,37 @@ void VTypeArray::write_range_to_stream_(std::ostream&fd) const
fd << ") ";
}
bool VTypeArray::write_special_case(std::ostream&fd) const
{
if(this == &primitive_SIGNED) {
fd << "signed";
} else if(this == &primitive_UNSIGNED) {
fd << "unsigned";
} else if(etype_ == &primitive_STDLOGIC) {
fd << "std_logic_vector";
} else if(etype_ == &primitive_BIT) {
fd << "bit_vector";
} else if(etype_ == &primitive_CHARACTER) {
fd << "string";
} else {
return false;
}
if(!ranges_.empty() && !ranges_[0].is_box()) {
write_range_to_stream_(fd);
}
return true;
}
void VTypeArray::write_type_to_stream(ostream&fd) const
{
// Special case: std_logic_vector
if (etype_ == &primitive_STDLOGIC) {
fd << "std_logic_vector";
if (! ranges_.empty() && ! ranges_[0].is_box()) {
write_range_to_stream_(fd);
}
return;
}
else if (etype_ == &primitive_CHARACTER) {
fd << "string";
if (! ranges_.empty() && ! ranges_[0].is_box()) {
write_range_to_stream_(fd);
}
return;
}
if(write_special_case(fd))
return;
fd << "array ";
// Unbounded array
if (! ranges_.empty()) {
assert(ranges_.size() < 2);
if (ranges_[0].is_box()) {
@ -165,9 +164,6 @@ void VTypePrimitive::write_to_stream(ostream&fd) const
case CHARACTER:
fd << "character";
break;
case BOOLEAN:
fd << "boolean";
break;
case TIME:
fd << "time";
break;
@ -183,7 +179,7 @@ void VTypeRange::write_to_stream(ostream&fd) const
// Detect some special cases that can be written as ieee or
// standard types.
if (const VTypePrimitive*tmp = dynamic_cast<const VTypePrimitive*> (base_)) {
if (start_==0 && end_==INT64_MAX && tmp->type()==VTypePrimitive::INTEGER) {
if (tmp->type()==VTypePrimitive::NATURAL) {
fd << "natural";
return;
}

View File

@ -156,16 +156,16 @@ static PLI_INT32 ivlh_attribute_event_calltf(ICARUS_VPI_CONST PLI_BYTE8*data)
rval.value.scalar = vpi1;
// Detect if there was any change
// Detect if change occured in this moment
if (mon->last_event.high != tnow.high)
rval.value.scalar = vpi0;
if (mon->last_event.low != tnow.low)
rval.value.scalar = vpi0;
// Determine the edge, if required
if (type == RISING_EDGE && mon->last_value.value.scalar == vpi0)
if (type == RISING_EDGE && mon->last_value.value.scalar != vpi1)
rval.value.scalar = vpi0;
else if (type == FALLING_EDGE && mon->last_value.value.scalar == vpi1)
else if (type == FALLING_EDGE && mon->last_value.value.scalar != vpi0)
rval.value.scalar = vpi0;
}