Merge pull request #92 from orsonmmz/vhdlpp_fixes

Vhdlpp fixes
This commit is contained in:
Stephen Williams 2016-03-07 09:05:36 -08:00
commit 6a8303bdaf
51 changed files with 2368 additions and 1158 deletions

View File

@ -328,39 +328,66 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
return false;
}
long lidx_tmp = sig->sb_to_idx(prefix_indices, lsb);
long midx_tmp = sig->sb_to_idx(prefix_indices, msb);
/* Detect reversed indices of a part select. */
if (lidx_tmp > midx_tmp) {
cerr << get_fileline() << ": error: Part select "
<< sig->name() << "[" << msb << ":"
<< lsb << "] indices reversed." << endl;
cerr << get_fileline() << ": : Did you mean "
<< sig->name() << "[" << lsb << ":"
<< msb << "]?" << endl;
long tmp = midx_tmp;
midx_tmp = lidx_tmp;
lidx_tmp = tmp;
des->errors += 1;
}
if (prefix_indices.size()+1 < sig->packed_dims().size()) {
// Here we have a slice that doesn't have enough indices
// to get to a single slice. For example:
// wire [9:0][5:1] foo
// ... foo[4:3] ...
// Make this work by finding the indexed slices and
// creating a generated slice that spans the whole
// range.
long loff, moff;
unsigned long lwid, mwid;
bool lrc;
lrc = sig->sb_to_slice(prefix_indices, lsb, loff, lwid);
ivl_assert(*this, lrc);
lrc = sig->sb_to_slice(prefix_indices, msb, moff, mwid);
ivl_assert(*this, lrc);
ivl_assert(*this, lwid == mwid);
/* Warn about a part select that is out of range. */
if (midx_tmp >= (long)sig->vector_width() || lidx_tmp < 0) {
cerr << get_fileline() << ": warning: Part select "
<< sig->name();
if (sig->unpacked_dimensions() > 0) {
cerr << "[]";
if (moff > loff) {
lidx = loff;
midx = moff + mwid - 1;
} else {
lidx = moff;
midx = loff + lwid - 1;
}
cerr << "[" << msb << ":" << lsb
<< "] is out of range." << endl;
}
/* This is completely out side the signal so just skip it. */
if (lidx_tmp >= (long)sig->vector_width() || midx_tmp < 0) {
return false;
}
} else {
long lidx_tmp = sig->sb_to_idx(prefix_indices, lsb);
long midx_tmp = sig->sb_to_idx(prefix_indices, msb);
midx = midx_tmp;
lidx = lidx_tmp;
/* Detect reversed indices of a part select. */
if (lidx_tmp > midx_tmp) {
cerr << get_fileline() << ": error: Part select "
<< sig->name() << "[" << msb << ":"
<< lsb << "] indices reversed." << endl;
cerr << get_fileline() << ": : Did you mean "
<< sig->name() << "[" << lsb << ":"
<< msb << "]?" << endl;
long tmp = midx_tmp;
midx_tmp = lidx_tmp;
lidx_tmp = tmp;
des->errors += 1;
}
/* Warn about a part select that is out of range. */
if (midx_tmp >= (long)sig->vector_width() || lidx_tmp < 0) {
cerr << get_fileline() << ": warning: Part select "
<< sig->name();
if (sig->unpacked_dimensions() > 0) {
cerr << "[]";
}
cerr << "[" << msb << ":" << lsb
<< "] is out of range." << endl;
}
/* This is completely out side the signal so just skip it. */
if (lidx_tmp >= (long)sig->vector_width() || midx_tmp < 0) {
return false;
}
midx = midx_tmp;
lidx = lidx_tmp;
}
break;
}

View File

@ -248,6 +248,25 @@ static NetExpr* make_sub_expr(long val, NetExpr*expr)
return res;
}
/*
* Subtract a signed constant from an existing expression.
*/
static NetExpr* make_sub_expr(NetExpr*expr, long val)
{
verinum val_v (val, expr->expr_width());
val_v.has_sign(true);
NetEConst*val_c = new NetEConst(val_v);
val_c->set_line(*expr);
NetEBAdd*res = new NetEBAdd('-', expr, val_c, expr->expr_width(),
expr->has_sign());
res->set_line(*expr);
return res;
}
/*
* Multiple an existing expression by a signed positive number.
* This does a lossless multiply, so the arguments will need to be
@ -434,17 +453,26 @@ NetExpr *normalize_variable_slice_base(const list<long>&indices, NetExpr*base,
-- pcur;
}
long sb;
if (pcur->get_msb() >= pcur->get_lsb())
sb = pcur->get_lsb();
else
sb = pcur->get_msb();
long sb = min(pcur->get_lsb(), pcur->get_msb());
long loff;
reg->sb_to_slice(indices, sb, loff, lwid);
bool idx_incr = pcur->get_msb() < pcur->get_lsb();
if(pcur->get_lsb() != 0) {
// Adjust the base for the case when the array range does not start from 0
if(idx_incr)
base = make_sub_expr(pcur->get_lsb(), base);
else
base = make_sub_expr(base, pcur->get_lsb());
}
base = make_mult_expr(base, lwid);
base = make_add_expr(base, loff);
// TODO I do not see any influence of the lines below to the test suite
if(!idx_incr)
base = make_add_expr(base, loff);
return base;
}
@ -1412,7 +1440,7 @@ bool evaluate_index_prefix(Design*des, NetScope*scope,
return false;
}
prefix_indices .push_back(tmp);
prefix_indices.push_back(tmp);
delete texpr;
}

View File

@ -29,7 +29,7 @@ using namespace std;
Architecture::Architecture(perm_string name, const ActiveScope&ref,
list<Architecture::Statement*>&s)
: Scope(ref), name_(name), cur_component_(NULL)
: Scope(ref), name_(name), cur_component_(NULL), cur_process_(NULL)
{
statements_.splice(statements_.end(), s);
}
@ -68,6 +68,14 @@ bool Architecture::find_constant(perm_string by_name, const VType*&typ, Expressi
return false;
}
Variable* Architecture::find_variable(perm_string by_name) const
{
if(cur_process_)
return cur_process_->find_variable(by_name);
return ScopeBase::find_variable(by_name);
}
void Architecture::push_genvar_type(perm_string gname, const VType*gtype)
{
genvar_type_t tmp;
@ -178,6 +186,21 @@ SignalAssignment::~SignalAssignment()
delete lval_;
}
CondSignalAssignment::CondSignalAssignment(ExpName*target, std::list<ExpConditional::case_t*>&options)
: lval_(target)
{
options_.splice(options_.end(), options);
}
CondSignalAssignment::~CondSignalAssignment()
{
delete lval_;
for(list<ExpConditional::case_t*>::iterator it = options_.begin();
it != options_.end(); ++it) {
delete *it;
}
}
ComponentInstantiation::ComponentInstantiation(perm_string i, perm_string c,
list<named_expr_t*>*parms,
list<named_expr_t*>*ports)
@ -245,9 +268,10 @@ StatementList::~StatementList()
}
ProcessStatement::ProcessStatement(perm_string iname,
const ActiveScope&ref,
std::list<Expression*>*sensitivity_list,
std::list<SequentialStmt*>*statements_list)
: StatementList(statements_list), iname_(iname)
: StatementList(statements_list), Scope(ref), iname_(iname)
{
if (sensitivity_list)
sensitivity_list_.splice(sensitivity_list_.end(), *sensitivity_list);

View File

@ -30,6 +30,7 @@ class Entity;
class Expression;
class ExpName;
class GenerateStatement;
class ProcessStatement;
class SequentialStmt;
class Signal;
class named_expr_t;
@ -65,9 +66,20 @@ class Architecture : public Scope, public LineInfo {
perm_string get_name() const { return name_; }
// Sets the currently processed component (to be able to reach its parameters).
void set_cur_component(ComponentInstantiation*component) { cur_component_ = component; }
bool find_constant(perm_string by_name, const VType*&typ, Expression*&exp) const;
Variable* find_variable(perm_string by_name) const;
// Sets the currently processed component (to be able to reach its parameters).
void set_cur_component(ComponentInstantiation*component) {
assert(!cur_component_ || !component);
cur_component_ = component;
}
// Sets the currently elaborated process (to use its scope for variable resolving).
void set_cur_process(ProcessStatement*process) {
assert(!cur_process_ || !process);
cur_process_ = process;
}
// Elaborate this architecture in the context of the given entity.
int elaborate(Entity*entity);
@ -113,7 +125,8 @@ class Architecture : public Scope, public LineInfo {
// Currently processed component (or NULL if none).
ComponentInstantiation*cur_component_;
private: // Not implemented
// Currently elaborated process (or NULL if none).
ProcessStatement*cur_process_;
};
/*
@ -189,6 +202,25 @@ class SignalAssignment : public Architecture::Statement {
std::list<Expression*> rval_;
};
class CondSignalAssignment : public Architecture::Statement {
public:
CondSignalAssignment(ExpName*target, std::list<ExpConditional::case_t*>&options);
~CondSignalAssignment();
int elaborate(Entity*ent, Architecture*arc);
int emit(ostream&out, Entity*entity, Architecture*arc);
void dump(ostream&out, int ident =0) const;
private:
ExpName*lval_;
std::list<ExpConditional::case_t*> options_;
// List of signals that should be emitted in the related process
// sensitivity list. It is filled during the elaboration step.
std::list<const ExpName*>sens_list_;
};
class ComponentInstantiation : public Architecture::Statement {
public:
@ -220,8 +252,16 @@ class StatementList : public Architecture::Statement {
StatementList(std::list<SequentialStmt*>*statement_list);
virtual ~StatementList();
virtual int elaborate(Entity*ent, Architecture*arc);
virtual int emit(ostream&out, Entity*entity, Architecture*arc);
int elaborate(Entity*ent, Architecture*arc) {
return elaborate(ent, static_cast<ScopeBase*>(arc));
}
int emit(ostream&out, Entity*ent, Architecture*arc) {
return emit(out, ent, static_cast<ScopeBase*>(arc));
}
virtual int elaborate(Entity*ent, ScopeBase*scope);
virtual int emit(ostream&out, Entity*entity, ScopeBase*scope);
virtual void dump(ostream&out, int indent =0) const;
std::list<SequentialStmt*>& stmt_list() { return statements_; }
@ -237,7 +277,7 @@ class InitialStatement : public StatementList {
InitialStatement(std::list<SequentialStmt*>*statement_list)
: StatementList(statement_list) {}
int emit(ostream&out, Entity*entity, Architecture*arc);
int emit(ostream&out, Entity*entity, ScopeBase*scope);
void dump(ostream&out, int indent =0) const;
};
@ -248,14 +288,15 @@ class FinalStatement : public StatementList {
FinalStatement(std::list<SequentialStmt*>*statement_list)
: StatementList(statement_list) {}
int emit(ostream&out, Entity*entity, Architecture*arc);
int emit(ostream&out, Entity*entity, ScopeBase*scope);
void dump(ostream&out, int indent =0) const;
};
class ProcessStatement : public StatementList {
class ProcessStatement : public StatementList, public Scope {
public:
ProcessStatement(perm_string iname,
const ActiveScope&ref,
std::list<Expression*>*sensitivity_list,
std::list<SequentialStmt*>*statement_list);
~ProcessStatement();
@ -265,9 +306,6 @@ class ProcessStatement : public StatementList {
void dump(ostream&out, int indent =0) const;
private:
int rewrite_as_always_edge_(Entity*ent, Architecture*arc);
int extract_anyedge_(Entity*ent, Architecture*arc);
perm_string iname_;
std::list<Expression*> sensitivity_list_;
};

View File

@ -95,6 +95,18 @@ void SignalAssignment::dump(ostream&out, int indent) const
}
}
void CondSignalAssignment::dump(ostream&out, int indent) const
{
out << setw(indent) << "" << "CondSignalAssignment file=" << get_fileline() << endl;
lval_->dump(out, indent+1);
out << setw(indent+2) << "" << "<= <expr>..." << endl;
for(list<ExpConditional::case_t*>::const_iterator it = options_.begin();
it != options_.end(); ++it) {
(*it)->dump(out, indent+2);
}
}
void StatementList::dump(ostream&out, int indent) const
{
out << setw(indent+3) << "" << "sequence of statements:" << endl;

View File

@ -45,25 +45,30 @@ int Architecture::elaborate(Entity*entity)
// Elaborate initializer expressions for signals & variables
for (map<perm_string,Signal*>::iterator cur = old_signals_.begin()
; cur != old_signals_.end() ; ++cur) {
cur->second->elaborate_init_expr(entity, this);
cur->second->elaborate(entity, this);
}
for (map<perm_string,Signal*>::iterator cur = new_signals_.begin()
; cur != new_signals_.end() ; ++cur) {
cur->second->elaborate_init_expr(entity, this);
cur->second->elaborate(entity, this);
}
for (map<perm_string,Variable*>::iterator cur = old_variables_.begin()
; cur != old_variables_.end() ; ++cur) {
cur->second->elaborate_init_expr(entity, this);
cur->second->elaborate(entity, this);
}
for (map<perm_string,Variable*>::iterator cur = new_variables_.begin()
; cur != new_variables_.end() ; ++cur) {
cur->second->elaborate_init_expr(entity, this);
cur->second->elaborate(entity, this);
}
// Elaborate subprograms
for (map<perm_string,SubprogramHeader*>::const_iterator cur = cur_subprograms_.begin()
for (map<perm_string,SubHeaderList>::const_iterator cur = cur_subprograms_.begin()
; cur != cur_subprograms_.end() ; ++cur) {
errors += cur->second->elaborate();
const SubHeaderList& subp_list = cur->second;
for(SubHeaderList::const_iterator it = subp_list.begin();
it != subp_list.end(); ++it) {
errors += (*it)->elaborate();
}
}
// Create 'initial' and 'final' blocks for implicit
// initalization and clean-up actions
@ -181,149 +186,33 @@ int IfGenerate::elaborate(Entity*ent, Architecture*arc)
return errors;
}
/*
* This method attempts to rewrite the process content as an
* always-@(n-edge <expr>) version of the same statement. This makes
* for a more natural translation to Verilog, if it comes to that.
*/
int ProcessStatement::rewrite_as_always_edge_(Entity*, Architecture*)
{
// If there are multiple sensitivity expressions, I give up.
if (sensitivity_list_.size() != 1)
return -1;
// If there are multiple statements, I give up.
if (stmt_list().size() != 1)
return -1;
Expression*se = sensitivity_list_.front();
SequentialStmt*stmt_raw = stmt_list().front();
// If the statement is not an if-statement, I give up.
IfSequential*stmt = dynamic_cast<IfSequential*> (stmt_raw);
if (stmt == 0)
return -1;
// If the "if" statement has a false clause, then give up.
if (stmt->false_size() != 0)
return -1;
const Expression*ce_raw = stmt->peek_condition();
// Here we expect the condition to be
// <name>'event AND <name>='1'.
// So if ce_raw is not a logical AND, I give up.
const ExpLogical*ce = dynamic_cast<const ExpLogical*> (ce_raw);
if (ce == 0)
return -1;
if (ce->logic_fun() != ExpLogical::AND)
return -1;
const Expression*op1_raw = ce->peek_operand1();
const Expression*op2_raw = ce->peek_operand2();
if (dynamic_cast<const ExpAttribute*>(op2_raw)) {
const Expression*tmp = op1_raw;
op1_raw = op2_raw;
op2_raw = tmp;
}
// If operand1 is not an 'event attribute, I give up.
const ExpObjAttribute*op1 = dynamic_cast<const ExpObjAttribute*>(op1_raw);
if (op1 == 0)
return -1;
if (op1->peek_attribute() != "event")
return -1;
const ExpRelation*op2 = dynamic_cast<const ExpRelation*>(op2_raw);
if (op2 == 0)
return -1;
if (op2->relation_fun() != ExpRelation::EQ)
return -1;
const Expression*op2a_raw = op2->peek_operand1();
const Expression*op2b_raw = op2->peek_operand2();
if (dynamic_cast<const ExpCharacter*>(op2a_raw)) {
const Expression*tmp = op2b_raw;
op2b_raw = op2a_raw;
op2a_raw = tmp;
}
if (! se->symbolic_compare(op1->peek_base()))
return -1;
const ExpCharacter*op2b = dynamic_cast<const ExpCharacter*>(op2b_raw);
if (op2b->value() != '1' && op2b->value() != '0')
return -1;
// We've matched this pattern:
// process (<se>) if (<se>'event and <se> = <op2b>) then ...
// And we can convert it to:
// always @(<N>edge <se>) ...
// Replace the sensitivity expression with an edge
// expression. The ExpEdge expression signals that this is an
// always-@(edge) statement.
ExpEdge*edge = new ExpEdge(op2b->value()=='1'? ExpEdge::POSEDGE : ExpEdge::NEGEDGE, 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(stmt_list().size() == 1);
stmt_list().pop_front();
stmt->extract_true(stmt_list());
delete stmt;
return 0;
}
int StatementList::elaborate(Entity*ent, Architecture*arc)
int StatementList::elaborate(Entity*ent, ScopeBase*scope)
{
int errors = 0;
for (std::list<SequentialStmt*>::iterator it = statements_.begin();
it != statements_.end(); ++it) {
errors += (*it)->elaborate(ent, arc);
errors += (*it)->elaborate(ent, scope);
}
return errors;
}
/*
* Change the "process (<expr>) <stmt>" into "always @(<expr>) ..."
*/
int ProcessStatement::extract_anyedge_(Entity*, Architecture*)
{
vector<Expression*> se;
while (! sensitivity_list_.empty()) {
se.push_back(sensitivity_list_.front());
sensitivity_list_.pop_front();
}
for (size_t idx = 0 ; idx < se.size() ; idx += 1) {
ExpEdge*edge = new ExpEdge(ExpEdge::ANYEDGE, se[idx]);
FILE_NAME(edge, se[idx]);
sensitivity_list_.push_back(edge);
}
return 0;
}
int ProcessStatement::elaborate(Entity*ent, Architecture*arc)
{
int errors = 0;
if (rewrite_as_always_edge_(ent, arc) >= 0) {
extract_anyedge_(ent, arc);
arc->set_cur_process(this);
for (map<perm_string,Variable*>::iterator cur = new_variables_.begin()
; cur != new_variables_.end() ; ++cur) {
cur->second->elaborate(ent, arc);
}
StatementList::elaborate(ent, arc);
arc->set_cur_process(NULL);
return errors;
}
@ -353,3 +242,48 @@ int SignalAssignment::elaborate(Entity*ent, Architecture*arc)
return errors;
}
int CondSignalAssignment::elaborate(Entity*ent, Architecture*arc)
{
int errors = 0;
// Visitor to extract signal names occuring in the conditional
// statements to create the sensitivity list
struct name_extractor_t : public ExprVisitor {
name_extractor_t(list<const ExpName*>& name_list)
: name_list_(name_list) {}
void operator() (Expression*s) {
if(const ExpName*name = dynamic_cast<const ExpName*>(s))
name_list_.push_back(name);
}
private:
list<const ExpName*>& name_list_;
} name_extractor(sens_list_);
// Elaborate the l-value expression.
errors += lval_->elaborate_lval(ent, arc, true);
// The elaborate_lval should have resolved the type of the
// l-value expression. We'll use that type to elaborate the
// r-value.
const VType*lval_type = lval_->peek_type();
if (lval_type == 0) {
if (errors == 0) {
errors += 1;
cerr << get_fileline()
<< ": error: Unable to calculate type for l-value expression."
<< endl;
}
return errors;
}
for(list<ExpConditional::case_t*>::iterator it = options_.begin();
it != options_.end(); ++it) {
ExpConditional::case_t*cas = (*it);
cas->elaborate_expr(ent, arc, lval_type);
cas->visit(name_extractor);
}
return errors;
}

View File

@ -23,42 +23,33 @@
# include "sequential.h"
# include "subprogram.h"
# include "vsignal.h"
# include "std_types.h"
# include <iostream>
# include <typeinfo>
# include <ivl_assert.h>
int Scope::emit_signals(ostream&out, Entity*entity, Architecture*arc)
int Scope::emit_signals(ostream&out, Entity*entity, ScopeBase*scope)
{
int errors = 0;
int errors = 0;
for (map<perm_string,Signal*>::iterator cur = old_signals_.begin()
; cur != old_signals_.end() ; ++cur) {
for (map<perm_string,Signal*>::iterator cur = new_signals_.begin()
; cur != new_signals_.end() ; ++cur) {
errors += cur->second->emit(out, entity, scope);
}
errors += cur->second->emit(out, entity, arc);
}
for (map<perm_string,Signal*>::iterator cur = new_signals_.begin()
; cur != new_signals_.end() ; ++cur) {
errors += cur->second->emit(out, entity, arc);
}
return errors;
return errors;
}
int Scope::emit_variables(ostream&out, Entity*entity, Architecture*arc)
int Scope::emit_variables(ostream&out, Entity*entity, ScopeBase*scope)
{
int errors = 0;
int errors = 0;
for (map<perm_string,Variable*>::iterator cur = old_variables_.begin()
; cur != old_variables_.end() ; ++cur) {
for (map<perm_string,Variable*>::iterator cur = new_variables_.begin()
; cur != new_variables_.end() ; ++cur) {
errors += cur->second->emit(out, entity, scope);
}
errors += cur->second->emit(out, entity, arc);
}
for (map<perm_string,Variable*>::iterator cur = new_variables_.begin()
; cur != new_variables_.end() ; ++cur) {
errors += cur->second->emit(out, entity, arc);
}
return errors;
return errors;
}
int Architecture::emit(ostream&out, Entity*entity)
@ -70,15 +61,16 @@ int Architecture::emit(ostream&out, Entity*entity)
// of the full definition.
typedef_context_t typedef_ctx;
//for (map<perm_string,const VType*>::iterator cur = use_types_.begin()
//; cur != use_types_.end() ; ++cur) {
for (map<perm_string,const VType*>::iterator cur = use_types_.begin()
; cur != use_types_.end() ; ++cur) {
if(is_global_type(cur->first))
continue;
//if(const VTypeDef*def = dynamic_cast<const VTypeDef*>(cur->second))
//errors += def->emit_typedef(out, typedef_ctx);
//}
if(const VTypeDef*def = dynamic_cast<const VTypeDef*>(cur->second))
errors += def->emit_typedef(out, typedef_ctx);
}
for (map<perm_string,const VType*>::iterator cur = cur_types_.begin()
; cur != cur_types_.end() ; ++cur) {
if(const VTypeDef*def = dynamic_cast<const VTypeDef*>(cur->second))
errors += def->emit_typedef(out, typedef_ctx);
}
@ -101,11 +93,18 @@ int Architecture::emit(ostream&out, Entity*entity)
errors += emit_signals(out, entity, this);
errors += emit_variables(out, entity, this);
for (map<perm_string,SubprogramHeader*>::const_iterator cur = cur_subprograms_.begin()
for (map<perm_string,SubHeaderList>::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())
errors += cur->second->emit_package(out);
const SubHeaderList& subp_list = cur->second;
for(SubHeaderList::const_iterator it = subp_list.begin();
it != subp_list.end(); ++it) {
SubprogramHeader*subp = *it;
// Do not emit unbounded functions, we will just need fixed instances later
if(!subp->unbounded())
errors += subp->emit_package(out);
}
}
for (list<Architecture::Statement*>::iterator cur = statements_.begin()
@ -130,19 +129,74 @@ int SignalAssignment::emit(ostream&out, Entity*ent, Architecture*arc)
int errors = 0;
ivl_assert(*this, rval_.size() == 1);
Expression*rval = rval_.front();
const Expression*rval = rval_.front();
out << "// " << get_fileline() << endl;
out << "assign ";
if(const ExpDelay*delayed = dynamic_cast<const ExpDelay*>(rval)) {
out << "#(";
delayed->peek_delay()->emit(out, ent, arc);
out << ") ";
rval = delayed->peek_expr();
}
errors += lval_->emit(out, ent, arc);
out << " = ";
errors += rval->emit(out, ent, arc);
out << ";" << endl;
return errors;
}
int CondSignalAssignment::emit(ostream&out, Entity*ent, Architecture*arc)
{
int errors = 0;
out << "// " << get_fileline() << endl;
out << "always @(";
bool first = true;
for(list<const ExpName*>::const_iterator it = sens_list_.begin();
it != sens_list_.end(); ++it) {
if(first)
first = false;
else
out << ",";
errors += (*it)->emit(out, ent, arc);
}
out << ") begin" << endl;
first = true;
for(list<ExpConditional::case_t*>::iterator it = options_.begin();
it != options_.end(); ++it) {
ExpConditional::case_t*cas = *it;
ivl_assert(*this, cas->true_clause().size() == 1);
const Expression*rval = cas->true_clause().front();
if(first)
first = false;
else
out << "else ";
if(Expression*cond = cas->condition()) {
out << "if(";
cond->emit(out, ent, arc);
out << ") ";
}
out << endl;
lval_->emit(out, ent, arc);
out << " = ";
rval->emit(out, ent, arc);
out << ";" << endl;
}
out << "end" << endl;
return errors;
}
int ComponentInstantiation::emit(ostream&out, Entity*ent, Architecture*arc)
{
const char*comma = "";
@ -246,31 +300,31 @@ int IfGenerate::emit(ostream&out, Entity*ent, Architecture*arc)
return errors;
}
int StatementList::emit(ostream&out, Entity*ent, Architecture*arc)
int StatementList::emit(ostream&out, Entity*ent, ScopeBase*scope)
{
int errors = 0;
for (std::list<SequentialStmt*>::iterator it = statements_.begin();
it != statements_.end(); ++it) {
errors += (*it)->emit(out, ent, arc);
errors += (*it)->emit(out, ent, scope);
}
return errors;
}
int InitialStatement::emit(ostream&out, Entity*ent, Architecture*arc)
int InitialStatement::emit(ostream&out, Entity*ent, ScopeBase*scope)
{
out << "initial begin" << endl;
int errors = StatementList::emit(out, ent, arc);
int errors = StatementList::emit(out, ent, scope);
out << "end" << endl;
return errors;
}
int FinalStatement::emit(ostream&out, Entity*ent, Architecture*arc)
int FinalStatement::emit(ostream&out, Entity*ent, ScopeBase*scope)
{
out << "final begin" << endl;
int errors = StatementList::emit(out, ent, arc);
int errors = StatementList::emit(out, ent, scope);
out << "end" << endl;
return errors;
@ -284,11 +338,25 @@ int FinalStatement::emit(ostream&out, Entity*ent, Architecture*arc)
* beginning. In VHDL, all the statements are initially executed once
* before blocking in the first wait on the sensitivity list.
*/
int ProcessStatement::emit(ostream&out, Entity*ent, Architecture*arc)
int ProcessStatement::emit(ostream&out, Entity*ent, Architecture*)
{
out << "always begin" << endl;
int errors = 0;
int errors = StatementList::emit(out, ent, arc);
/* Check if the process has no sensitivity list and ends up with
* a final wait. If so, convert the process to an initial block. */
const WaitStmt*wait_stmt = NULL;
if (!stmt_list().empty())
wait_stmt = dynamic_cast<const WaitStmt*>(stmt_list().back());
if (wait_stmt && wait_stmt->type() == WaitStmt::FINAL)
out << "initial begin : ";
else
out << "always begin : ";
out << peek_name() << endl;
errors += emit_variables(out, ent, this);
errors += StatementList::emit(out, ent, this);
if (! sensitivity_list_.empty()) {
out << "@(";
@ -297,13 +365,12 @@ int ProcessStatement::emit(ostream&out, Entity*ent, Architecture*arc)
; cur != sensitivity_list_.end() ; ++cur) {
if (comma) out << comma;
errors += (*cur)->emit(out, ent, arc);
errors += (*cur)->emit(out, ent, this);
comma = ", ";
}
out << ") /* sensitivity list for process */;" << endl;
out << "); /* sensitivity list for process */" << endl;
}
out << "end" << endl;
out << "end /* " << peek_name() << " */" << endl;
return errors;
}

View File

@ -21,3 +21,5 @@
StringHeapLex lex_strings;
StringHeapLex filename_strings;
StringHeapLex gen_strings;

View File

@ -30,8 +30,13 @@ extern bool verbose_flag;
extern bool debug_elaboration;
extern std::ofstream debug_log_file;
// Stores strings created by the lexer
extern StringHeapLex lex_strings;
// Stores file names
extern StringHeapLex filename_strings;
// Stores generated strigns (e.g. scope names)
extern StringHeapLex gen_strings;
#endif /* IVL_compiler_H */

View File

@ -150,22 +150,35 @@ void ScopeBase::dump_scope(ostream&out) const
}
// Dump subprograms
out << " -- Imported Subprograms" << endl;
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;
for (map<perm_string,SubHeaderList>::const_iterator cur = use_subprograms_.begin()
; cur != cur_subprograms_.end() ; ++ cur) {
const SubHeaderList& subp_list = cur->second;
for(SubHeaderList::const_iterator it = subp_list.begin();
it != subp_list.end(); ++it) {
const SubprogramHeader*subp = *it;
out << " subprogram " << cur->first << " is" << endl;
subp->dump(out);
if(subp->body())
subp->body()->dump(out);
out << " end subprogram " << cur->first << endl;
}
}
out << " -- Subprograms from this scope" << endl;
for (map<perm_string,SubprogramHeader*>::const_iterator cur = cur_subprograms_.begin()
for (map<perm_string,SubHeaderList>::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;
const SubHeaderList& subp_list = cur->second;
for(SubHeaderList::const_iterator it = subp_list.begin();
it != subp_list.end(); ++it) {
const SubprogramHeader*subp = *it;
out << " subprogram " << cur->first << " is" << endl;
subp->dump(out);
if(subp->body())
subp->body()->dump(out);
out << " end subprogram " << cur->first << endl;
}
}
// Dump component declarations
out << " -- Components" << endl;
@ -382,10 +395,13 @@ void ExpName::dump(ostream&out, int indent) const
<< " at " << get_fileline() << endl;
if (prefix_.get())
prefix_->dump(out, indent+8);
if (index_)
index_->dump(out, indent+6);
if (lsb_)
lsb_->dump(out, indent+6);
if (indices_) {
for(list<Expression*>::const_iterator it = indices_->begin();
it != indices_->end(); ++it) {
(*it)->dump(out, indent+6);
}
}
}
void ExpNameALL::dump(ostream&out, int indent) const

View File

@ -1,6 +1,7 @@
/*
* Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2012-2015 / Stephen Williams (steve@icarus.com),
* Copyright CERN 2016
* @author Maciej Suminski (maciej.suminski@cern.ch)
*
* This source code is free software; you can redistribute it
@ -86,12 +87,17 @@ list<Expression*>*ExpAttribute::clone_args() const {
void ExpAttribute::visit_args(ExprVisitor& func)
{
func.down();
func(this);
if(args_) {
for(list<Expression*>::iterator it = args_->begin();
for(list<Expression*>::iterator it = args_->begin();
it != args_->end(); ++it) {
func(*it);
}
(*it)->visit(func);
}
}
func.up();
}
ExpObjAttribute::ExpObjAttribute(ExpName*base, perm_string name, list<Expression*>*args)
@ -110,11 +116,13 @@ Expression*ExpObjAttribute::clone() const
name_, clone_args());
}
void ExpObjAttribute::visit(ExprVisitor& func)
void ExpObjAttribute::visit(ExprVisitor&func)
{
func.down();
func(this);
visit_args(func);
base_->visit(func);
func(this);
func.up();
}
ExpTypeAttribute::ExpTypeAttribute(const VType*base, perm_string name, list<Expression*>*args)
@ -127,10 +135,12 @@ Expression*ExpTypeAttribute::clone() const
return new ExpTypeAttribute(base_, name_, clone_args());
}
void ExpTypeAttribute::visit(ExprVisitor& func)
void ExpTypeAttribute::visit(ExprVisitor&func)
{
visit_args(func);
func.down();
func(this);
visit_args(func);
func.up();
}
const perm_string ExpAttribute::LEFT = perm_string::literal("left");
@ -157,11 +167,13 @@ bool ExpBinary::eval_operand2(Entity*ent, ScopeBase*scope, int64_t&val) const
return operand2_->evaluate(ent, scope, val);
}
void ExpBinary::visit(ExprVisitor& func)
void ExpBinary::visit(ExprVisitor&func)
{
func.down();
func(this);
operand1_->visit(func);
operand2_->visit(func);
func(this);
func.up();
}
ExpUnary::ExpUnary(Expression*op1)
@ -174,10 +186,12 @@ ExpUnary::~ExpUnary()
delete operand1_;
}
void ExpUnary::visit(ExprVisitor& func)
void ExpUnary::visit(ExprVisitor&func)
{
operand1_->visit(func);
func.down();
func(this);
operand1_->visit(func);
func.up();
}
ExpAggregate::ExpAggregate(std::list<element_t*>*el)
@ -224,8 +238,11 @@ Expression* ExpAggregate::clone() const
return new ExpAggregate(new_elements);
}
void ExpAggregate::visit(ExprVisitor& func)
void ExpAggregate::visit(ExprVisitor&func)
{
func.down();
func(this);
for(std::vector<element_t*>::iterator it = elements_.begin();
it != elements_.end(); ++it) {
(*it)->extract_expression()->visit(func);
@ -239,7 +256,7 @@ void ExpAggregate::visit(ExprVisitor& func)
it->expr->visit(func);
}
func(this);
func.up();
}
ExpAggregate::choice_t::choice_t(Expression*exp)
@ -363,11 +380,13 @@ ExpConcat::~ExpConcat()
delete operand2_;
}
void ExpConcat::visit(ExprVisitor& func)
void ExpConcat::visit(ExprVisitor&func)
{
operand1_->visit(func);
operand2_->visit(func);
func(this);
func.down();
func(this);
operand1_->visit(func);
operand2_->visit(func);
func.up();
}
ExpConditional::ExpConditional(Expression*co, list<Expression*>*tru,
@ -401,14 +420,16 @@ Expression*ExpConditional::clone() const
return new ExpConditional(NULL, NULL, new_options);
}
void ExpConditional::visit(ExprVisitor& func)
void ExpConditional::visit(ExprVisitor&func)
{
for(std::list<case_t*>::iterator it = options_.begin();
it != options_.end(); ++it) {
(*it)->visit(func);
}
func.down();
func(this);
for(std::list<case_t*>::iterator it = options_.begin();
it != options_.end(); ++it)
(*it)->visit(func);
func.up();
}
ExpConditional::case_t::case_t(Expression*cond, std::list<Expression*>*tru)
@ -470,15 +491,16 @@ Expression*ExpSelected::clone() const
return new ExpSelected(selector_->clone(), new_options);
}
void ExpConditional::case_t::visit(ExprVisitor& func)
void ExpConditional::case_t::visit(ExprVisitor&func)
{
func.down();
if(cond_)
func(cond_);
cond_->visit(func);
for(std::list<Expression*>::iterator it = true_clause_.begin();
it != true_clause_.end(); ++it) {
func(*it);
}
it != true_clause_.end(); ++it)
(*it)->visit(func);
func.up();
}
ExpEdge::ExpEdge(ExpEdge::fun_t typ, Expression*op)
@ -528,14 +550,18 @@ Expression*ExpFunc::clone() const {
return f;
}
void ExpFunc::visit(ExprVisitor& func) {
void ExpFunc::visit(ExprVisitor&func)
{
func.down();
func(this);
if(!argv_.empty()) {
for(std::vector<Expression*>::iterator it = argv_.begin();
it != argv_.end(); ++it)
(*it)->visit(func);
}
func(this);
func.up();
}
const VType* ExpFunc::func_ret_type() const
@ -577,41 +603,54 @@ ExpLogical::~ExpLogical()
}
ExpName::ExpName(perm_string nn)
: name_(nn), index_(0), lsb_(0)
: name_(nn), indices_(NULL)
{
}
ExpName::ExpName(perm_string nn, list<Expression*>*indices)
: name_(nn), index_(0), lsb_(0)
{
/* For now, assume a single index. */
ivl_assert(*this, indices->size() == 1);
index_ = indices->front();
indices->pop_front();
}
ExpName::ExpName(perm_string nn, Expression*msb, Expression*lsb)
: name_(nn), index_(msb), lsb_(lsb)
{
ivl_assert(*this, !msb || msb != lsb);
}
ExpName::ExpName(ExpName*prefix, perm_string nn)
: prefix_(prefix), name_(nn), index_(0), lsb_(0)
: name_(nn), indices_(indices)
{
}
ExpName::ExpName(ExpName*prefix, perm_string nn, Expression*msb, Expression*lsb)
: prefix_(prefix), name_(nn), index_(msb), lsb_(lsb)
ExpName::ExpName(ExpName*prefix, perm_string nn, std::list<Expression*>*indices)
: prefix_(prefix), name_(nn), indices_(indices)
{
ivl_assert(*this, !msb || msb != lsb);
}
ExpName::~ExpName()
{
delete index_;
delete lsb_;
if(indices_) {
for(list<Expression*>::iterator it = indices_->begin();
it != indices_->end(); ++it) {
delete *it;
}
delete indices_;
}
}
Expression*ExpName::clone() const {
list<Expression*>*new_indices = NULL;
if(indices_) {
new_indices = new list<Expression*>();
for(list<Expression*>::const_iterator it = indices_->begin();
it != indices_->end(); ++it) {
new_indices->push_back((*it)->clone());
}
}
return new ExpName(static_cast<ExpName*>(safe_clone(prefix_.get())),
name_, new_indices);
}
void ExpName::add_index(std::list<Expression*>*idx)
{
if(!indices_)
indices_ = new list<Expression*>();
indices_->splice(indices_->end(), *idx);
}
bool ExpName::symbolic_compare(const Expression*that) const
@ -623,42 +662,69 @@ bool ExpName::symbolic_compare(const Expression*that) const
if (name_ != that_name->name_)
return false;
if (that_name->index_ && !index_)
if (that_name->indices_ && !indices_)
return false;
if (index_ && !that_name->index_)
if (indices_ && !that_name->indices_)
return false;
if (index_) {
assert(that_name->index_);
return index_->symbolic_compare(that_name->index_);
if (indices_) {
assert(that_name->indices_);
if(indices_->size() != that_name->indices_->size())
return false;
list<Expression*>::const_iterator it, jt;
it = indices_->begin();
jt = that_name->indices_->begin();
for(unsigned int i = 0; i < indices_->size(); ++i) {
if(!(*it)->symbolic_compare(*jt))
return false;
++it;
++jt;
}
}
return true;
}
void ExpName::set_range(Expression*msb, Expression*lsb)
Expression*ExpName::index(unsigned int number) const
{
assert(index_==0);
index_ = msb;
assert(lsb_==0);
lsb_ = lsb;
if(!indices_)
return NULL;
if(number >= indices_->size())
return NULL;
if(number == 0)
return indices_->front();
list<Expression*>::const_iterator it = indices_->begin();
advance(it, number);
return *it;
}
void ExpName::visit(ExprVisitor& func)
void ExpName::visit(ExprVisitor&func)
{
func.down();
func(this);
if(prefix_.get())
prefix_.get()->visit(func);
if(index_)
index_->visit(func);
if(indices_) {
for(list<Expression*>::const_iterator it = indices_->begin();
it != indices_->end(); ++it) {
(*it)->visit(func);
}
}
if(lsb_)
lsb_->visit(func);
func(this);
func.up();
}
int ExpName::index_t::emit(ostream&out, Entity*ent, ScopeBase*scope)
int ExpName::index_t::emit(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
@ -689,6 +755,37 @@ ExpRelation::~ExpRelation()
{
}
ExpScopedName::ExpScopedName(perm_string scope, ExpName*exp)
: scope_name_(scope), scope_(NULL), name_(exp)
{
}
ExpScopedName::~ExpScopedName()
{
delete name_;
}
void ExpScopedName::visit(ExprVisitor&func)
{
func.down();
func(this);
name_->visit(func);
func.up();
}
ScopeBase*ExpScopedName::get_scope(const ScopeBase*scope)
{
if(!scope_)
scope_ = scope->find_scope(scope_name_);
return scope_;
}
ScopeBase*ExpScopedName::get_scope(const ScopeBase*scope) const
{
return scope_ ? scope_ : scope->find_scope(scope_name_);
}
ExpShift::ExpShift(ExpShift::shift_t op, Expression*op1, Expression*op2)
: ExpBinary(op1, op2), shift_(op)
{
@ -730,10 +827,12 @@ ExpCast::~ExpCast()
{
}
void ExpCast::visit(ExprVisitor& func)
void ExpCast::visit(ExprVisitor&func)
{
base_->visit(func);
func.down();
func(this);
base_->visit(func);
func.up();
}
ExpNew::ExpNew(Expression*size) :
@ -746,10 +845,12 @@ ExpNew::~ExpNew()
delete size_;
}
void ExpNew::visit(ExprVisitor& func)
void ExpNew::visit(ExprVisitor&func)
{
size_->visit(func);
func.down();
func(this);
size_->visit(func);
func.up();
}
ExpTime::ExpTime(uint64_t amount, timeunit_t unit)
@ -845,3 +946,23 @@ Expression*ExpRange::right()
ExpAttribute::RIGHT, NULL);
return right_;
}
ExpDelay::ExpDelay(Expression*expr, Expression*delay)
: expr_(expr), delay_(delay)
{
}
ExpDelay::~ExpDelay()
{
delete expr_;
delete delay_;
}
void ExpDelay::visit(ExprVisitor&func)
{
func.down();
func(this);
expr_->visit(func);
delay_->visit(func);
func.up();
}

View File

@ -3,6 +3,7 @@
/*
* Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com)
* Copyright CERN 2015 / Stephen Williams (steve@icarus.com),
* Copyright CERN 2016
* @author Maciej Suminski (maciej.suminski@cern.ch)
*
* This source code is free software; you can redistribute it
@ -28,6 +29,7 @@
# include <list>
# include <memory>
# include <vector>
# include <cassert>
class ExpRange;
class ScopeBase;
@ -37,9 +39,25 @@ class VTypeArray;
class VTypePrimitive;
class ExpName;
/*
* Helper class to recursively traverse an expression tree
* (i.e. complex expressions).
*/
struct ExprVisitor {
virtual ~ExprVisitor() {};
ExprVisitor() : level_(0) {}
virtual ~ExprVisitor() {}
virtual void operator() (Expression*s) = 0;
// Methods to manage recursion depth. Every Expression::visit() method
// should call down() in the beginning and up() in the end.
inline void down() { ++level_; }
inline void up() { --level_; assert(level_ >= 0); }
protected:
int level() const { return level_; }
private:
int level_;
};
/*
@ -96,11 +114,11 @@ class Expression : public LineInfo {
// The emit virtual method is called by architecture emit to
// output the generated code for the expression. The derived
// class fills in the details of what exactly happened.
virtual int emit(ostream&out, Entity*ent, ScopeBase*scope) =0;
virtual int emit(ostream&out, Entity*ent, ScopeBase*scope) const =0;
// The emit_package virtual message is similar, but is called
// in a package context and to emit SV packages.
virtual int emit_package(std::ostream&out);
virtual int emit_package(std::ostream&out) const;
// The evaluate virtual method tries to evaluate expressions
// to constant literal values. Return true and set the val
@ -125,7 +143,7 @@ class Expression : public LineInfo {
virtual ostream& dump_inline(ostream&out) const;
// Recursively visits a tree of expressions (useful for complex expressions).
virtual void visit(ExprVisitor& func) { func(this); }
virtual void visit(ExprVisitor& func) { func.down(); func(this); func.up(); }
protected:
// This function is called by the derived class during
@ -175,7 +193,7 @@ class ExpUnary : public Expression {
inline void write_to_stream_operand1(std::ostream&fd) const
{ operand1_->write_to_stream(fd); }
int emit_operand1(ostream&out, Entity*ent, ScopeBase*scope);
int emit_operand1(ostream&out, Entity*ent, ScopeBase*scope) const;
void dump_operand1(ostream&out, int indent = 0) const;
private:
@ -201,8 +219,8 @@ class ExpBinary : public Expression {
protected:
int elaborate_exprs(Entity*, ScopeBase*, const VType*);
int emit_operand1(ostream&out, Entity*ent, ScopeBase*scope);
int emit_operand2(ostream&out, Entity*ent, ScopeBase*scope);
int emit_operand1(ostream&out, Entity*ent, ScopeBase*scope) const;
int emit_operand2(ostream&out, Entity*ent, ScopeBase*scope) const;
bool eval_operand1(Entity*ent, ScopeBase*scope, int64_t&val) const;
bool eval_operand2(Entity*ent, ScopeBase*scope, int64_t&val) const;
@ -307,15 +325,15 @@ class ExpAggregate : public Expression {
const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const;
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&fd) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
void dump(ostream&out, int indent = 0) const;
void visit(ExprVisitor& func);
private:
int elaborate_expr_array_(Entity*ent, ScopeBase*scope, const VTypeArray*ltype);
int elaborate_expr_record_(Entity*ent, ScopeBase*scope, const VTypeRecord*ltype);
int emit_array_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeArray*ltype);
int emit_record_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeRecord*ltype);
int emit_array_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeArray*ltype) const;
int emit_record_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeRecord*ltype) const;
private:
// This is the elements as directly parsed.
@ -341,7 +359,7 @@ class ExpArithmetic : public ExpBinary {
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&fd) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
virtual bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
void dump(ostream&out, int indent = 0) const;
@ -366,7 +384,9 @@ class ExpAttribute : public Expression {
protected:
std::list<Expression*>*clone_args() const;
int elaborate_args(Entity*ent, ScopeBase*scope, const VType*ltype);
void visit_args(ExprVisitor& func);
bool evaluate_type_attr(const VType*type, Entity*ent, ScopeBase*scope, int64_t&val) const;
bool test_array_type(const VType*type) const;
@ -383,7 +403,7 @@ class ExpObjAttribute : public ExpAttribute {
inline const ExpName* peek_base() const { return base_; }
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
const VType*probe_type(Entity*ent, ScopeBase*scope) const;
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&fd) const;
@ -405,7 +425,7 @@ class ExpTypeAttribute : public ExpAttribute {
inline const VType* peek_base() const { return base_; }
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
const VType*probe_type(Entity*ent, ScopeBase*scope) const;
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&fd) const;
@ -431,7 +451,7 @@ class ExpBitstring : public Expression {
const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const;
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&fd) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
void dump(ostream&out, int indent = 0) const;
private:
@ -451,7 +471,7 @@ class ExpCharacter : public Expression {
const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const;
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&fd) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
bool is_primary(void) const;
void dump(ostream&out, int indent = 0) const;
@ -459,7 +479,7 @@ class ExpCharacter : public Expression {
private:
int emit_primitive_bit_(ostream&out, Entity*ent, ScopeBase*scope,
const VTypePrimitive*etype);
const VTypePrimitive*etype) const;
private:
char value_;
@ -479,7 +499,7 @@ class ExpConcat : public Expression {
const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const;
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&fd) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
bool is_primary(void) const;
void dump(ostream&out, int indent = 0) const;
void visit(ExprVisitor& func);
@ -506,12 +526,13 @@ class ExpConditional : public Expression {
case_t(const case_t&other);
~case_t();
inline Expression*condition() { return cond_; }
inline Expression*condition() const { return cond_; }
inline void set_condition(Expression*cond) { cond_ = cond; }
inline const std::list<Expression*>& true_clause() const { return true_clause_; }
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*lt);
int emit_option(ostream&out, Entity*ent, ScopeBase*scope);
int emit_default(ostream&out, Entity*ent, ScopeBase*scope);
int emit_option(ostream&out, Entity*ent, ScopeBase*scope) const;
int emit_default(ostream&out, Entity*ent, ScopeBase*scope) const;
void dump(ostream&out, int indent = 0) const;
std::list<Expression*>& extract_true_clause() { return true_clause_; }
void visit(ExprVisitor& func);
@ -531,7 +552,7 @@ class ExpConditional : public Expression {
const VType*probe_type(Entity*ent, ScopeBase*scope) const;
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&fd) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
void dump(ostream&out, int indent = 0) const;
void visit(ExprVisitor& func);
@ -571,7 +592,7 @@ class ExpEdge : public ExpUnary {
inline fun_t edge_fun() const { return fun_; }
void write_to_stream(std::ostream&fd) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
void dump(ostream&out, int indent = 0) const;
private:
@ -597,7 +618,7 @@ class ExpFunc : public Expression {
const VType*probe_type(Entity*ent, ScopeBase*scope) const;
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&fd) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
void dump(ostream&out, int indent = 0) const;
void visit(ExprVisitor& func); // NOTE: does not handle expressions in subprogram
@ -619,8 +640,8 @@ class ExpInteger : public Expression {
const VType*probe_type(Entity*ent, ScopeBase*scope) const;
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&fd) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit_package(std::ostream&out);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
int emit_package(std::ostream&out) const;
bool is_primary(void) const { return true; }
bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
void dump(ostream&out, int indent = 0) const;
@ -642,8 +663,8 @@ class ExpReal : public Expression {
const VType*probe_type(Entity*ent, ScopeBase*scope) const;
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&fd) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit_package(std::ostream&out);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
int emit_package(std::ostream&out) const;
bool is_primary(void) const;
void dump(ostream&out, int indent = 0) const;
virtual ostream& dump_inline(ostream&out) const;
@ -669,7 +690,7 @@ class ExpLogical : public ExpBinary {
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&fd) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
void dump(ostream&out, int indent = 0) const;
private:
@ -686,30 +707,26 @@ class ExpName : public Expression {
public:
explicit ExpName(perm_string nn);
ExpName(perm_string nn, std::list<Expression*>*indices);
ExpName(perm_string nn, Expression*msb, Expression*lsb);
ExpName(ExpName*prefix, perm_string nn);
ExpName(ExpName*prefix, perm_string nn, Expression*msb, Expression*lsb);
~ExpName();
ExpName(ExpName*prefix, perm_string nn, std::list<Expression*>*indices = NULL);
virtual ~ExpName();
public: // Base methods
Expression*clone() const {
return new ExpName(static_cast<ExpName*>(safe_clone(prefix_.get())),
name_, safe_clone(index_), safe_clone(lsb_));
}
Expression*clone() const;
int elaborate_lval(Entity*ent, ScopeBase*scope, bool);
int elaborate_rval(Entity*ent, ScopeBase*scope, const InterfacePort*);
const VType* probe_type(Entity*ent, ScopeBase*scope) const;
const VType* fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*host) const;
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&fd) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit_indices(ostream&out, Entity*ent, ScopeBase*scope) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
bool is_primary(void) const;
bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
bool symbolic_compare(const Expression*that) const;
void dump(ostream&out, int indent = 0) const;
inline const char* name() const { return name_; }
inline const perm_string& peek_name() const { return name_; }
void set_range(Expression*msb, Expression*lsb);
void add_index(std::list<Expression*>*idx);
void visit(ExprVisitor& func);
private:
@ -723,7 +740,7 @@ class ExpName : public Expression {
delete offset_;
}
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
private:
Expression*idx_;
@ -737,14 +754,14 @@ class ExpName : public Expression {
const VType* probe_prefix_type_(Entity*ent, ScopeBase*scope) const;
const VType* probe_prefixed_type_(Entity*ent, ScopeBase*scope) const;
int emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope);
int emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope) const;
// There are some workarounds required for constant arrays/records, as
// they are currently emitted as flat localparams (without any type
// information). The following workarounds adjust the access indices
// to select appropriate parts of the localparam.
bool try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope,
list<index_t*>&indices, int&data_size);
list<index_t*>&indices, int&data_size) const;
bool check_const_array_workaround_(const VTypeArray*arr, ScopeBase*scope,
list<index_t*>&indices, int&data_size) const;
@ -753,19 +770,20 @@ class ExpName : public Expression {
list<index_t*>&indices, int&data_size) const;
int emit_workaround_(ostream&out, Entity*ent, ScopeBase*scope,
const list<index_t*>&indices, int field_size);
const list<index_t*>&indices, int field_size) const;
private:
Expression*index(unsigned int number) const;
std::auto_ptr<ExpName> prefix_;
perm_string name_;
Expression*index_;
Expression*lsb_;
std::list<Expression*>*indices_;
};
class ExpNameALL : public ExpName {
public:
ExpNameALL() : ExpName(perm_string()) { }
ExpNameALL() : ExpName(empty_perm_string) { }
public:
const VType* probe_type(Entity*ent, ScopeBase*scope) const;
@ -790,13 +808,71 @@ class ExpRelation : public ExpBinary {
const VType* probe_type(Entity*ent, ScopeBase*scope) const;
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&fd) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
void dump(ostream&out, int indent = 0) const;
private:
fun_t fun_;
};
/*
* Helper class to handle name expressions coming from another scope. As such,
* we get more information regarding their type, etc. from the associated scope.
*/
class ExpScopedName : public Expression {
public:
ExpScopedName(perm_string scope, ExpName*exp);
~ExpScopedName();
Expression*clone() const
{ return new ExpScopedName(scope_name_, static_cast<ExpName*>(name_->clone())); }
int elaborate_lval(Entity*ent, ScopeBase*scope, bool is_sequ)
{ return name_->elaborate_lval(ent, get_scope(scope), is_sequ); }
int elaborate_rval(Entity*ent, ScopeBase*scope, const InterfacePort*lval)
{ return name_->elaborate_rval(ent, get_scope(scope), lval); }
const VType* probe_type(Entity*ent, ScopeBase*scope) const
{ return name_->probe_type(ent, get_scope(scope)); }
const VType* fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*host) const
{ return name_->fit_type(ent, get_scope(scope), host); }
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype)
{ return name_->elaborate_expr(ent, get_scope(scope), ltype); }
void write_to_stream(std::ostream&fd) const
{ name_->write_to_stream(fd); }
int emit(ostream&out, Entity*ent, ScopeBase*scope) const {
out << scope_name_ << ".";
return name_->emit(out, ent, scope);
}
bool is_primary(void) const
{ return name_->is_primary(); }
bool evaluate(Entity*ent, ScopeBase*, int64_t&val) const
{ return name_->evaluate(ent, scope_, val); }
bool symbolic_compare(const Expression*that) const
{ return name_->symbolic_compare(that); }
void dump(ostream&out, int indent = 0) const;
void visit(ExprVisitor&func);
private:
// Functions that resolve the origin scope for the name expression
ScopeBase*get_scope(const ScopeBase*scope);
ScopeBase*get_scope(const ScopeBase*scope) const;
perm_string scope_name_;
ScopeBase*scope_;
ExpName*name_;
};
class ExpShift : public ExpBinary {
public:
enum shift_t { SRL, SLL, SRA, SLA, ROL, ROR };
@ -810,7 +886,7 @@ class ExpShift : public ExpBinary {
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&fd) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
void dump(ostream&out, int indent = 0) const;
@ -830,7 +906,7 @@ class ExpString : public Expression {
const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const;
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&fd) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
bool is_primary(void) const;
void dump(ostream&out, int indent = 0) const;
const std::string& get_value() const { return value_; }
@ -840,7 +916,7 @@ class ExpString : public Expression {
static std::string escape_quot(const std::string& str);
private:
int emit_as_array_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeArray*arr);
int emit_as_array_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeArray*arr) const;
private:
std::string value_;
@ -855,7 +931,7 @@ class ExpUAbs : public ExpUnary {
Expression*clone() const { return new ExpUAbs(peek_operand()->clone()); }
void write_to_stream(std::ostream&fd) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
void dump(ostream&out, int indent = 0) const;
};
@ -868,7 +944,7 @@ class ExpUNot : public ExpUnary {
Expression*clone() const { return new ExpUNot(peek_operand()->clone()); }
void write_to_stream(std::ostream&fd) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
void dump(ostream&out, int indent = 0) const;
};
@ -887,7 +963,7 @@ class ExpCast : public Expression {
return base_->elaborate_expr(ent, scope, type_);
}
void write_to_stream(std::ostream&fd) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
void dump(ostream&out, int indent = 0) const;
void visit(ExprVisitor& func);
@ -910,7 +986,7 @@ class ExpNew : public Expression {
// There is no 'new' in VHDL - do not emit anything
void write_to_stream(std::ostream&) const {};
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
void dump(ostream&out, int indent = 0) const;
void visit(ExprVisitor& func);
@ -928,7 +1004,7 @@ class ExpTime : public Expression {
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
//bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
void dump(ostream&out, int indent = 0) const;
@ -963,7 +1039,7 @@ class ExpRange : public Expression {
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
void dump(ostream&out, int indent = 0) const;
private:
// Regular range related fields
@ -979,8 +1055,26 @@ class ExpRange : public Expression {
bool range_reverse_;
};
// Elaborates an expression used as an argument in a procedure/function call.
int elaborate_argument(Expression*expr, const SubprogramHeader*subp,
int idx, Entity*ent, ScopeBase*scope);
// Helper class that wraps other expression to specify delay.
class ExpDelay : public Expression {
public:
ExpDelay(Expression*expr, Expression*delay);
~ExpDelay();
Expression*clone() const { return new ExpDelay(expr_->clone(), delay_->clone()); }
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
void dump(ostream&out, int indent = 0) const;
void visit(ExprVisitor& func);
const Expression*peek_expr() const { return expr_; }
const Expression*peek_delay() const { return delay_; }
private:
Expression*expr_;
Expression*delay_;
};
#endif /* IVL_expression_H */

View File

@ -71,7 +71,7 @@ void ExpConcat::dump(ostream&out, int indent) const
void ExpCast::dump(ostream&out, int indent) const
{
out << "Casting ";
out << setw(indent) << "" << "Casting ";
base_->dump(out, indent+4);
out << " to ";
type_->emit_def(out, empty_perm_string);
@ -79,10 +79,17 @@ void ExpCast::dump(ostream&out, int indent) const
void ExpNew::dump(ostream&out, int indent) const
{
out << "New dynamic array size: ";
out << setw(indent) << "" << "New dynamic array size: " << endl;
size_->dump(out, indent);
}
void ExpScopedName::dump(ostream&out, int indent) const
{
out << setw(indent) << "" << "Scoped name expression: " << endl;
out << " scope " << scope_name_ << " " << scope_ << endl;
name_->dump(out, indent+4);
}
void ExpShift::dump(ostream&out, int indent) const
{
const char*fun_name = "?";
@ -123,3 +130,11 @@ void ExpRange::dump(ostream&out, int indent) const
out << setw(indent) << "" << "Range ";
write_to_stream(out);
}
void ExpDelay::dump(ostream&out, int indent) const
{
out << setw(indent) << "" << "Expression ";
expr_->write_to_stream(out);
out << " delayed by ";
delay_->write_to_stream(out);
}

View File

@ -1,6 +1,8 @@
/*
* Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com)
* Copyright CERN 2016
* @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
@ -66,24 +68,26 @@ const VType*ExpName::elaborate_adjust_type_with_range_(Entity*ent, ScopeBase*sco
}
if (const VTypeArray*array = dynamic_cast<const VTypeArray*>(type)) {
if (index_ && !lsb_) {
// If the name is an array or a vector, then an
// indexed name has the type of the element.
type = array->element_type();
Expression*idx = index(0);
} else if (index_ && lsb_) {
if (ExpRange*range = dynamic_cast<ExpRange*>(idx)) {
// If the name is an array, then a part select is
// also an array, but with different bounds.
int64_t use_msb, use_lsb;
bool flag;
flag = index_->evaluate(ent, scope, use_msb);
flag = range->msb()->evaluate(ent, scope, use_msb);
ivl_assert(*this, flag);
flag = lsb_->evaluate(ent, scope, use_lsb);
flag = range->lsb()->evaluate(ent, scope, use_lsb);
ivl_assert(*this, flag);
type = new VTypeArray(array->element_type(), use_msb, use_lsb);
}
else if(idx) {
// If the name is an array or a vector, then an
// indexed name has the type of the element.
type = array->element_type();
}
}
return type;
@ -97,10 +101,14 @@ int ExpName::elaborate_lval_(Entity*ent, ScopeBase*scope, bool is_sequ, ExpName*
debug_log_file << get_fileline() << ": ExpName::elaborate_lval_: "
<< "name_=" << name_
<< ", suffix->name()=" << suffix->name();
if (index_)
debug_log_file << ", index_=" << *index_;
if (lsb_)
debug_log_file << ", lsb_=" << *lsb_;
if (indices_) {
for(list<Expression*>::const_iterator it = indices_->begin();
it != indices_->end(); ++it) {
debug_log_file << "[";
debug_log_file << **it;
debug_log_file << "]";
}
}
debug_log_file << endl;
}
@ -342,8 +350,10 @@ const VType* ExpBinary::probe_type(Entity*ent, ScopeBase*scope) const
if (t2 == 0)
return t1;
if (t1 == t2)
if (t1->type_match(t2))
return t1;
if (t2->type_match(t1))
return t2;
if (const VType*tb = resolve_operand_types_(t1, t2))
return tb;
@ -577,16 +587,33 @@ const VType* ExpArithmetic::resolve_operand_types_(const VType*t1, const VType*t
if (t1->type_match(t2))
return t1;
if (t2->type_match(t2))
return t2;
return 0;
}
int ExpAttribute::elaborate_args(Entity*ent, ScopeBase*scope, const VType*ltype)
{
int errors = 0;
if(args_) {
for(list<Expression*>::iterator it = args_->begin();
it != args_->end(); ++it) {
errors += (*it)->elaborate_expr(ent, scope, ltype);
}
}
return errors;
}
int ExpObjAttribute::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*)
{
int errors = 0;
const VType*sub_type = base_->probe_type(ent, scope);
return base_->elaborate_expr(ent, scope, sub_type);
errors += elaborate_args(ent, scope, sub_type);
errors += base_->elaborate_expr(ent, scope, sub_type);
return errors;
}
const VType* ExpObjAttribute::probe_type(Entity*, ScopeBase*) const
@ -597,10 +624,9 @@ const VType* ExpObjAttribute::probe_type(Entity*, ScopeBase*) const
return NULL;
}
int ExpTypeAttribute::elaborate_expr(Entity*, ScopeBase*, const VType*)
int ExpTypeAttribute::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype)
{
// This is just to mute warnings, there is nothing to elaborate here
return 0;
return elaborate_args(ent, scope, ltype);
}
const VType* ExpTypeAttribute::probe_type(Entity*, ScopeBase*) const
@ -763,20 +789,29 @@ int ExpConditional::case_t::elaborate_expr(Entity*ent, ScopeBase*scope, const VT
return errors;
}
const VType*ExpFunc::probe_type(Entity*, ScopeBase*scope) const
const VType*ExpFunc::probe_type(Entity*ent, ScopeBase*scope) const
{
SubprogramHeader*prog = def_;
if(!prog) {
prog = scope->find_subprogram(name_);
}
list<const VType*> arg_types;
if(!prog)
prog = library_find_subprogram(name_);
for(vector<Expression*>::const_iterator it = argv_.begin();
it != argv_.end(); ++it) {
arg_types.push_back((*it)->probe_type(ent, scope));
}
if(!prog) {
cerr << get_fileline() << ": sorry: VHDL function " << name_ << " not yet implemented" << endl;
ivl_assert(*this, false);
prog = scope->match_subprogram(name_, &arg_types);
if(!prog)
prog = library_match_subprogram(name_, &arg_types);
if(!prog) {
cerr << get_fileline() << ": sorry: could not find function ";
emit_subprogram_sig(cerr, name_, arg_types);
cerr << endl;
ivl_assert(*this, false);
}
}
return prog->peek_return_type();
@ -786,31 +821,37 @@ int ExpFunc::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*)
{
int errors = 0;
ivl_assert(*this, scope);
SubprogramHeader*prog = scope->find_subprogram(name_);
ivl_assert(*this, def_ == 0); // do not elaborate twice
if(!prog)
prog = library_find_subprogram(name_);
// Create a list of argument types to find a matching subprogram
list<const VType*> arg_types;
for(vector<Expression*>::iterator it = argv_.begin();
it != argv_.end(); ++it)
arg_types.push_back((*it)->probe_type(ent, scope));
ivl_assert(*this, def_==0);
def_ = prog;
def_ = scope->match_subprogram(name_, &arg_types);
if(!def_)
def_ = library_match_subprogram(name_, &arg_types);
if(!def_) {
cerr << get_fileline() << ": error: could not find function ";
emit_subprogram_sig(cerr, name_, arg_types);
cerr << endl;
return 1;
}
// Elaborate arguments
for (size_t idx = 0; idx < argv_.size(); ++idx) {
errors += elaborate_argument(argv_[idx], prog, idx, ent, scope);
errors += def_->elaborate_argument(argv_[idx], idx, ent, scope);
}
// 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;
def_ = def_->make_instance(argv_, scope);
name_ = def_->name(); // TODO necessary?
}
return errors;
@ -823,7 +864,10 @@ const VType* ExpFunc::fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*) c
const VType* ExpInteger::probe_type(Entity*, ScopeBase*) const
{
return &primitive_INTEGER;
if(value_ >= 0)
return &primitive_NATURAL;
else
return &primitive_INTEGER;
}
int ExpInteger::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype)
@ -888,40 +932,49 @@ const VType* ExpName::probe_prefix_type_(Entity*ent, ScopeBase*scope) const
*/
const VType* ExpName::probe_prefixed_type_(Entity*ent, ScopeBase*scope) const
{
// First, get the type of the prefix.
// First, get the type of the prefix.
const VType*prefix_type = prefix_->probe_prefix_type_(ent, scope);
if (prefix_type == 0) {
return 0;
return 0;
}
while (const VTypeDef*def = dynamic_cast<const VTypeDef*> (prefix_type)) {
prefix_type = def->peek_definition();
prefix_type = def->peek_definition();
}
// If the prefix type is a record, then the current name is
// the name of a member.
if (const VTypeRecord*pref_record = dynamic_cast<const VTypeRecord*> (prefix_type)) {
const VTypeRecord::element_t*element = pref_record->element_by_name(name_);
ivl_assert(*this, element);
const VType*element_type = prefix_type;
bool type_changed = true;
const VType*element_type = element->peek_type();
ivl_assert(*this, element_type);
// Keep unwinding the type until we find the basic element type
while (type_changed) {
type_changed = false;
return element_type;
// If the prefix type is a record, then the current name is
// the name of a member.
if (const VTypeRecord*pref_record = dynamic_cast<const VTypeRecord*>(element_type)) {
const VTypeRecord::element_t*element = pref_record->element_by_name(name_);
ivl_assert(*this, element);
element_type = element->peek_type();
ivl_assert(*this, element_type);
type_changed = true;
}
if (const VTypeArray*pref_array = dynamic_cast<const VTypeArray*>(element_type)) {
element_type = pref_array->basic_type(false);
ivl_assert(*this, element_type);
type_changed = true;
}
}
if (const VTypeArray*pref_array = dynamic_cast<const VTypeArray*> (prefix_type)) {
const VType*element_type = pref_array->element_type();
ivl_assert(*this, element_type);
return element_type;
if(!element_type) {
cerr << get_fileline() << ": sorry: I don't know how to probe "
<< "prefix type " << typeid(*prefix_type).name()
<< " of " << name_ << "." << endl;
return NULL;
}
cerr << get_fileline() << ": sorry: I don't know how to probe "
<< "prefix type " << typeid(*prefix_type).name()
<< " of " << name_ << "." << endl;
return 0;
return element_type;
}
const VType* ExpName::probe_type(Entity*ent, ScopeBase*scope) const
@ -967,8 +1020,14 @@ const VType* ExpName::probe_type(Entity*ent, ScopeBase*scope) const
}
}
cerr << get_fileline() << ": error: Signal/variable " << name_
<< " not found in this context." << endl;
if(ent || scope) {
// Do not display error messages if there was no entity or scope
// specified. There are functions that are called without any specific
// context and they still may want to probe the expression type.
cerr << get_fileline() << ": error: Signal/variable " << name_
<< " not found in this context." << endl;
}
return 0;
}
@ -987,11 +1046,12 @@ int ExpName::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*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);
if (indices_) {
for(list<Expression*>::const_iterator it = indices_->begin();
it != indices_->end(); ++it) {
(*it)->elaborate_expr(ent, scope, &primitive_INTEGER);
}
}
return 0;
}
@ -1080,27 +1140,12 @@ int ExpRange::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*)
return errors;
}
int elaborate_argument(Expression*expr, const SubprogramHeader*subp,
int idx, Entity*ent, ScopeBase*scope)
int ExpDelay::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype)
{
const VType*type = expr->probe_type(ent, scope);
int errors = 0;
if(subp) {
const InterfacePort*param = subp->peek_param(idx);
errors += expr_->elaborate_expr(ent, scope, ltype);
errors += delay_->elaborate_expr(ent, scope, ltype);
// Enable reg_flag for variables that might be modified in subprograms
if(param->mode == PORT_OUT || param->mode == PORT_INOUT) {
if(const ExpName*e = dynamic_cast<const ExpName*>(expr)) {
if(Signal*sig = scope->find_signal(e->peek_name()))
sig->count_ref_sequ();
else if(Variable*var = scope->find_variable(e->peek_name()))
var->count_ref_sequ();
}
}
if(!type)
type = param->type;
}
return expr->elaborate_expr(ent, scope, type);
return errors;
}

View File

@ -62,7 +62,7 @@ inline static int emit_logic(char val, ostream& out, const VTypePrimitive::type_
return 0;
}
int Expression::emit(ostream&out, Entity*, ScopeBase*)
int Expression::emit(ostream&out, Entity*, ScopeBase*) const
{
out << " /* " << get_fileline() << ": internal error: "
<< "I don't know how to emit this expression! "
@ -70,7 +70,7 @@ int Expression::emit(ostream&out, Entity*, ScopeBase*)
return 1;
}
int Expression::emit_package(ostream&out)
int Expression::emit_package(ostream&out) const
{
out << " /* " << get_fileline() << ": internal error: "
<< "I don't know how to emit_package this expression! "
@ -83,7 +83,7 @@ bool Expression::is_primary(void) const
return false;
}
int ExpBinary::emit_operand1(ostream&out, Entity*ent, ScopeBase*scope)
int ExpBinary::emit_operand1(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
bool oper_primary = operand1_->is_primary();
@ -93,7 +93,7 @@ int ExpBinary::emit_operand1(ostream&out, Entity*ent, ScopeBase*scope)
return errors;
}
int ExpBinary::emit_operand2(ostream&out, Entity*ent, ScopeBase*scope)
int ExpBinary::emit_operand2(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
bool oper_primary = operand2_->is_primary();
@ -103,14 +103,14 @@ int ExpBinary::emit_operand2(ostream&out, Entity*ent, ScopeBase*scope)
return errors;
}
int ExpUnary::emit_operand1(ostream&out, Entity*ent, ScopeBase*scope)
int ExpUnary::emit_operand1(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
errors += operand1_->emit(out, ent, scope);
return errors;
}
int ExpAggregate::emit(ostream&out, Entity*ent, ScopeBase*scope)
int ExpAggregate::emit(ostream&out, Entity*ent, ScopeBase*scope) const
{
if (peek_type() == 0) {
out << "/* " << get_fileline() << ": internal error: "
@ -134,7 +134,7 @@ int ExpAggregate::emit(ostream&out, Entity*ent, ScopeBase*scope)
return 1;
}
int ExpAggregate::emit_array_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeArray*atype)
int ExpAggregate::emit_array_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeArray*atype) const
{
int errors = 0;
@ -194,8 +194,8 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, ScopeBase*scope, const VT
if(use_msb < use_lsb)
swap(use_msb, use_lsb);
map<int64_t,choice_element*> element_map;
choice_element*element_other = 0;
map<int64_t,const choice_element*> element_map;
const choice_element*element_other = 0;
bool positional_section = true;
int64_t positional_idx = use_msb;
@ -283,7 +283,7 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, ScopeBase*scope, const VT
out << "{";
for (int64_t idx = use_msb ; idx >= use_lsb ; idx -= 1) {
choice_element*cur = element_map[idx];
const choice_element*cur = element_map[idx];
if (cur == 0)
cur = element_other;
@ -303,7 +303,7 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, ScopeBase*scope, const VT
return errors;
}
int ExpAggregate::emit_record_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeRecord*)
int ExpAggregate::emit_record_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeRecord*) const
{
int errors = 0;
@ -331,7 +331,7 @@ int ExpAggregate::emit_record_(ostream&out, Entity*ent, ScopeBase*scope, const V
return errors;
}
int ExpObjAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope)
int ExpObjAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
@ -372,7 +372,7 @@ int ExpObjAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope)
return errors;
}
int ExpTypeAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope)
int ExpTypeAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
@ -409,7 +409,7 @@ int ExpTypeAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope)
return errors;
}
int ExpArithmetic::emit(ostream&out, Entity*ent, ScopeBase*scope)
int ExpArithmetic::emit(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
@ -463,7 +463,7 @@ int ExpArithmetic::emit(ostream&out, Entity*ent, ScopeBase*scope)
return errors;
}
int ExpBitstring::emit(ostream&out, Entity*, ScopeBase*)
int ExpBitstring::emit(ostream&out, Entity*, ScopeBase*) const
{
int errors = 0;
@ -475,7 +475,7 @@ int ExpBitstring::emit(ostream&out, Entity*, ScopeBase*)
}
int ExpCharacter::emit_primitive_bit_(ostream&out, Entity*, ScopeBase*,
const VTypePrimitive*etype)
const VTypePrimitive*etype) const
{
out << "1'b";
int res = emit_logic(value_, out, etype->type());
@ -488,7 +488,7 @@ int ExpCharacter::emit_primitive_bit_(ostream&out, Entity*, ScopeBase*,
return res;
}
int ExpCharacter::emit(ostream&out, Entity*ent, ScopeBase*scope)
int ExpCharacter::emit(ostream&out, Entity*ent, ScopeBase*scope) const
{
const VType*etype = peek_type();
const VTypeArray*array;
@ -519,7 +519,7 @@ bool ExpConcat::is_primary(void) const
return true;
}
int ExpConcat::emit(ostream&out, Entity*ent, ScopeBase*scope)
int ExpConcat::emit(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
out << "{";
@ -530,7 +530,7 @@ int ExpConcat::emit(ostream&out, Entity*ent, ScopeBase*scope)
return errors;
}
int ExpConditional::emit(ostream&out, Entity*ent, ScopeBase*scope)
int ExpConditional::emit(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
out << "(";
@ -538,10 +538,10 @@ int ExpConditional::emit(ostream&out, Entity*ent, ScopeBase*scope)
// Draw out any when-else expressions. These are all the else_
// clauses besides the last.
if (options_.size() > 1) {
list<case_t*>::iterator last = options_.end();
list<case_t*>::const_iterator last = options_.end();
--last;
for (list<case_t*>::iterator cur = options_.begin()
for (list<case_t*>::const_iterator cur = options_.begin()
; cur != last ; ++cur) {
errors += (*cur)->emit_option(out, ent, scope);
}
@ -560,7 +560,7 @@ int ExpConditional::emit(ostream&out, Entity*ent, ScopeBase*scope)
return errors;
}
int ExpConditional::case_t::emit_option(ostream&out, Entity*ent, ScopeBase*scope)
int ExpConditional::case_t::emit_option(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
assert(cond_ != 0);
@ -582,7 +582,7 @@ int ExpConditional::case_t::emit_option(ostream&out, Entity*ent, ScopeBase*scope
return errors;
}
int ExpConditional::case_t::emit_default(ostream&out, Entity*ent, ScopeBase*scope)
int ExpConditional::case_t::emit_default(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
// Trailing else must have no condition.
@ -599,7 +599,7 @@ int ExpConditional::case_t::emit_default(ostream&out, Entity*ent, ScopeBase*scop
return errors;
}
int ExpEdge::emit(ostream&out, Entity*ent, ScopeBase*scope)
int ExpEdge::emit(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
switch (fun_) {
@ -616,7 +616,7 @@ int ExpEdge::emit(ostream&out, Entity*ent, ScopeBase*scope)
return errors;
}
int ExpFunc::emit(ostream&out, Entity*ent, ScopeBase*scope)
int ExpFunc::emit(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
@ -625,16 +625,7 @@ int ExpFunc::emit(ostream&out, Entity*ent, ScopeBase*scope)
return 1;
}
// 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() << " ::";
errors += def_->emit_name(argv_, out, ent, scope);
def_->emit_full_name(argv_, out, ent, scope);
out << " (";
def_->emit_args(argv_, out, ent, scope);
out << ")";
@ -642,25 +633,25 @@ int ExpFunc::emit(ostream&out, Entity*ent, ScopeBase*scope)
return errors;
}
int ExpInteger::emit(ostream&out, Entity*, ScopeBase*)
int ExpInteger::emit(ostream&out, Entity*, ScopeBase*) const
{
out << "32'd" << value_;
return 0;
}
int ExpInteger::emit_package(ostream&out)
int ExpInteger::emit_package(ostream&out) const
{
out << value_;
return 0;
}
int ExpReal::emit(ostream&out, Entity*, ScopeBase*)
int ExpReal::emit(ostream&out, Entity*, ScopeBase*) const
{
out << value_;
return 0;
}
int ExpReal::emit_package(ostream&out)
int ExpReal::emit_package(ostream&out) const
{
out << value_;
return 0;
@ -671,7 +662,7 @@ bool ExpReal::is_primary(void) const
return true;
}
int ExpLogical::emit(ostream&out, Entity*ent, ScopeBase*scope)
int ExpLogical::emit(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
@ -703,7 +694,23 @@ int ExpLogical::emit(ostream&out, Entity*ent, ScopeBase*scope)
return errors;
}
int ExpName::emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope)
int ExpName::emit_indices(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
if (indices_) {
for(list<Expression*>::const_iterator it = indices_->begin();
it != indices_->end(); ++it) {
out << "[";
errors += (*it)->emit(out, ent, scope);
out << "]";
}
}
return errors;
}
int ExpName::emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
if (prefix_.get()) {
@ -711,17 +718,12 @@ int ExpName::emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope)
}
out << "\\" << name_ << " ";
if (index_) {
out << "[";
errors += index_->emit(out, ent, scope);
out << "]";
ivl_assert(*this, lsb_ == 0);
}
errors += emit_indices(out, ent, scope);
out << ".";
return errors;
}
int ExpName::emit(ostream&out, Entity*ent, ScopeBase*scope)
int ExpName::emit(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
int field_size = 0;
@ -748,26 +750,19 @@ int ExpName::emit(ostream&out, Entity*ent, ScopeBase*scope)
else
out << "\\" << name_ << " ";
if (index_) {
out << "[";
errors += index_->emit(out, ent, scope);
if (lsb_) {
out << ":";
errors += lsb_->emit(out, ent, scope);
}
out << "]";
}
errors += emit_indices(out, ent, scope);
return errors;
}
bool ExpName::try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope,
list<index_t*>& indices, int& data_size)
list<index_t*>& indices, int& data_size) const
{
Expression*exp = NULL;
bool wrkand_required = false;
const VType*type = NULL;
Expression*idx = index(0);
ExpRange*range = dynamic_cast<ExpRange*>(idx);
if(!scope)
return false;
@ -775,7 +770,7 @@ bool ExpName::try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope,
if(prefix_.get())
prefix_->try_workarounds_(out, ent, scope, indices, data_size);
if(index_ && !lsb_ && scope->find_constant(name_, type, exp)) {
if(idx && !range && scope->find_constant(name_, type, exp)) {
while(const VTypeDef*type_def = dynamic_cast<const VTypeDef*>(type)) {
type = type_def->peek_definition();
}
@ -787,7 +782,7 @@ bool ExpName::try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope,
if(prefix_.get() && scope->find_constant(prefix_->name_, type, exp)) {
// Handle the case of array of records
if(prefix_->index_) {
if(prefix_->index(0)) {
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(type);
assert(arr);
type = arr->element_type();
@ -804,17 +799,23 @@ bool ExpName::try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope,
wrkand_required |= check_const_record_workaround_(rec, scope, indices, data_size);
}
// Workarounds are currently implemented only for one-dimensional arrays
assert(!indices_ || indices_->size() == 1 || !wrkand_required);
return wrkand_required;
}
bool ExpName::check_const_array_workaround_(const VTypeArray*arr,
ScopeBase*scope, list<index_t*>&indices, int&data_size) const
{
assert(indices_ && indices_->size() == 1);
const VType*element = arr->element_type();
data_size = element->get_width(scope);
if(data_size < 0)
return false;
indices.push_back(new index_t(index_->clone(), new ExpInteger(data_size)));
indices.push_back(new index_t(index(0)->clone(), new ExpInteger(data_size)));
return true;
}
@ -839,7 +840,7 @@ bool ExpName::check_const_record_workaround_(const VTypeRecord*rec,
data_size = tmp_field;
indices.push_back(new index_t(NULL, NULL, new ExpInteger(tmp_offset)));
if(index_) {
if(index(0)) {
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(type);
assert(arr);
return check_const_array_workaround_(arr, scope, indices, data_size);
@ -860,7 +861,7 @@ bool ExpName::check_const_record_workaround_(const VTypeRecord*rec,
}
int ExpName::emit_workaround_(ostream&out, Entity*ent, ScopeBase*scope,
const list<index_t*>& indices, int field_size)
const list<index_t*>& indices, int field_size) const
{
int errors = 0;
@ -882,14 +883,26 @@ bool ExpName::is_primary(void) const
return true;
}
int ExpRelation::emit(ostream&out, Entity*ent, ScopeBase*scope)
int ExpRelation::emit(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
errors += emit_operand1(out, ent, scope);
const VType*type1 = peek_operand1()->probe_type(ent, scope);
const VType*type2 = peek_operand2()->probe_type(ent, scope);
bool logical_compare = false;
// Apply case equality operator if any of the operands is of logic type
if(((type1 && (type1->type_match(&primitive_STDLOGIC) ||
type1->type_match(&primitive_STDLOGIC_VECTOR)))
|| (type2 && (type2->type_match(&primitive_STDLOGIC) ||
type2->type_match(&primitive_STDLOGIC_VECTOR))))) {
logical_compare = true;
}
switch (fun_) {
case EQ:
out << " == ";
out << (logical_compare ? " === " : " == ");
break;
case LT:
out << " < ";
@ -898,7 +911,7 @@ int ExpRelation::emit(ostream&out, Entity*ent, ScopeBase*scope)
out << " > ";
break;
case NEQ:
out << " != ";
out << (logical_compare ? " !== " : " != ");
break;
case LE:
out << " <= ";
@ -912,7 +925,7 @@ int ExpRelation::emit(ostream&out, Entity*ent, ScopeBase*scope)
return errors;
}
int ExpShift::emit(ostream&out, Entity*ent, ScopeBase*scope)
int ExpShift::emit(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
@ -947,7 +960,7 @@ bool ExpString::is_primary(void) const
return true;
}
int ExpString::emit(ostream& out, Entity*ent, ScopeBase*scope)
int ExpString::emit(ostream& out, Entity*ent, ScopeBase*scope) const
{
const VTypeArray*arr;
const VType*type = peek_type();
@ -962,7 +975,7 @@ int ExpString::emit(ostream& out, Entity*ent, ScopeBase*scope)
return 0;
}
int ExpString::emit_as_array_(ostream& out, Entity*, ScopeBase*, const VTypeArray*arr)
int ExpString::emit_as_array_(ostream& out, Entity*, ScopeBase*, const VTypeArray*arr) const
{
int errors = 0;
assert(arr->dimensions() == 1);
@ -1010,7 +1023,7 @@ std::string ExpString::escape_quot(const std::string& str)
return result;
}
int ExpUAbs::emit(ostream&out, Entity*ent, ScopeBase*scope)
int ExpUAbs::emit(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
out << "abs(";
@ -1019,7 +1032,7 @@ int ExpUAbs::emit(ostream&out, Entity*ent, ScopeBase*scope)
return errors;
}
int ExpUNot::emit(ostream&out, Entity*ent, ScopeBase*scope)
int ExpUNot::emit(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
@ -1035,7 +1048,7 @@ int ExpUNot::emit(ostream&out, Entity*ent, ScopeBase*scope)
return errors;
}
int ExpCast::emit(ostream&out, Entity*ent, ScopeBase*scope)
int ExpCast::emit(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
errors += type_->emit_def(out, empty_perm_string);
@ -1045,7 +1058,7 @@ int ExpCast::emit(ostream&out, Entity*ent, ScopeBase*scope)
return errors;
}
int ExpNew::emit(ostream&out, Entity*ent, ScopeBase*scope)
int ExpNew::emit(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
out << "new[";
@ -1054,7 +1067,7 @@ int ExpNew::emit(ostream&out, Entity*ent, ScopeBase*scope)
return errors;
}
int ExpTime::emit(ostream&out, Entity*, ScopeBase*)
int ExpTime::emit(ostream&out, Entity*, ScopeBase*) const
{
out << amount_;
@ -1070,7 +1083,7 @@ int ExpTime::emit(ostream&out, Entity*, ScopeBase*)
return 0;
}
int ExpRange::emit(ostream&out, Entity*ent, ScopeBase*scope)
int ExpRange::emit(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
@ -1089,5 +1102,17 @@ int ExpRange::emit(ostream&out, Entity*ent, ScopeBase*scope)
errors += right_->emit(out, ent, scope);
}
return 0;
return errors;
}
int ExpDelay::emit(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
out << "#(";
errors += delay_->emit(out, ent, scope);
out << ") ";
errors += expr_->emit(out, ent, scope);
return errors;
}

View File

@ -147,12 +147,13 @@ bool ExpName::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const
if (ent) {
const InterfacePort*gen = ent->find_generic(name_);
if (gen) {
cerr << get_fileline() << ": sorry: I don't necessarily "
<< "handle generic overrides." << endl;
// Evaluate the default expression and use that.
if (gen->expr)
return gen->expr->evaluate(ent, scope, val);
if (gen->expr && gen->expr->evaluate(ent, scope, val))
return true;
cerr << get_fileline() << ": sorry: I could not evaluate "
<< "generic override." << endl;
return false;
}
}

View File

@ -181,9 +181,32 @@ void ExpReal::write_to_stream(ostream&fd) const
fd << value_;
}
void ExpLogical::write_to_stream(ostream&) const
void ExpLogical::write_to_stream(ostream&out) const
{
ivl_assert(*this, !"Not supported");
peek_operand1()->write_to_stream(out);
switch (fun_) {
case AND:
out << " and ";
break;
case OR:
out << " or ";
break;
case XOR:
out << " xor ";
break;
case NAND:
out << " nand ";
break;
case NOR:
out << " nor ";
break;
case XNOR:
out << " xnor ";
break;
}
peek_operand2()->write_to_stream(out);
}
void ExpName::write_to_stream(ostream&fd) const
@ -194,14 +217,20 @@ void ExpName::write_to_stream(ostream&fd) const
}
fd << name_;
if (index_) {
fd << "(";
index_->write_to_stream(fd);
if (lsb_) {
fd << " downto ";
lsb_->write_to_stream(fd);
}
fd << ")";
if (indices_) {
fd << "(";
bool first = true;
for(list<Expression*>::const_iterator it = indices_->begin();
it != indices_->end(); ++it) {
if(first)
first = false;
else
fd << ",";
(*it)->write_to_stream(fd);
}
fd << ")";
}
}
@ -334,3 +363,10 @@ void ExpRange::write_to_stream(ostream&fd) const
right_->write_to_stream(fd);
}
}
void ExpDelay::write_to_stream(ostream&out) const
{
expr_->write_to_stream(out);
out << " after ";
delay_->write_to_stream(out);
}

View File

@ -1,6 +1,8 @@
/*
* Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
* Copyright CERN 2016
* @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
@ -73,9 +75,9 @@ void library_add_directory(const char*directory)
library_search_path.push_front(directory);
}
SubprogramHeader*library_find_subprogram(perm_string name)
SubprogramHeader*library_match_subprogram(perm_string name, const list<const VType*>*params)
{
SubprogramHeader*subp = NULL;
SubprogramHeader*subp;
map<perm_string,struct library_contents>::const_iterator lib_it;
for(lib_it = libraries.begin(); lib_it != libraries.end(); ++lib_it) {
@ -83,7 +85,7 @@ SubprogramHeader*library_find_subprogram(perm_string name)
map<perm_string,Package*>::const_iterator pack_it;
for(pack_it = lib.packages.begin(); pack_it != lib.packages.end(); ++pack_it) {
if((subp = pack_it->second->find_subprogram(name)))
if((subp = pack_it->second->match_subprogram(name, params)))
return subp;
}
}
@ -370,6 +372,7 @@ static void import_std_use(const YYLTYPE&loc, ActiveScope*res, perm_string packa
res->use_name(perm_string::literal("text"), &primitive_INTEGER);
res->use_name(perm_string::literal("line"), &primitive_STRING);
res->use_name(type_FILE_OPEN_KIND.peek_name(), &type_FILE_OPEN_KIND);
res->use_name(type_FILE_OPEN_STATUS.peek_name(), &type_FILE_OPEN_STATUS);
return;
} else {
sorrymsg(loc, "package %s of library %s not yet supported", package.str(), name.str());

View File

@ -19,15 +19,18 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
class SubprogramHeader;
#include <list>
extern void library_set_work_path(const char*work_path);
extern void library_add_directory(const char*directory);
class SubprogramHeader;
class VType;
void library_set_work_path(const char*work_path);
void library_add_directory(const char*directory);
int elaborate_libraries(void);
int emit_packages(void);
extern SubprogramHeader*library_find_subprogram(perm_string name);
SubprogramHeader*library_match_subprogram(perm_string name, const list<const VType*>*params);
#endif /* IVL_library_H */

View File

@ -24,6 +24,8 @@
# include "parse_misc.h"
# include "std_types.h"
# include "ivl_assert.h"
# include <list>
# include <iterator>
Package::Package(perm_string n, const ActiveScope&ref)
: Scope(ref), name_(n)
@ -45,9 +47,15 @@ int Package::elaborate()
{
int errors = 0;
for (map<perm_string,SubprogramHeader*>::const_iterator cur = cur_subprograms_.begin()
; cur != cur_subprograms_.end() ; ++cur) {
errors += cur->second->elaborate();
for (map<perm_string,SubHeaderList>::iterator cur = cur_subprograms_.begin()
; cur != cur_subprograms_.end() ; ++ cur) {
SubHeaderList& subp_list = cur->second;
for(SubHeaderList::iterator it = subp_list.begin();
it != subp_list.end(); ++it) {
(*it)->set_package(this);
errors += (*it)->elaborate();
}
}
return errors;
@ -67,9 +75,6 @@ void Package::write_to_stream(ostream&fd) const
// and identifiers.
for (map<perm_string,const VType*>::const_iterator cur = use_types_.begin()
; cur != use_types_.end() ; ++cur) {
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))
@ -79,9 +84,6 @@ void Package::write_to_stream(ostream&fd) const
}
for (map<perm_string,const VType*>::const_iterator cur = cur_types_.begin()
; cur != cur_types_.end() ; ++cur) {
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))
@ -92,31 +94,11 @@ void Package::write_to_stream(ostream&fd) const
for (map<perm_string,const VType*>::const_iterator cur = use_types_.begin()
; cur != use_types_.end() ; ++cur) {
// Do not include global types in types dump
if (is_global_type(cur->first))
continue;
if(!dynamic_cast<const VTypeDef*>(cur->second))
fd << "sub";
fd << "type " << cur->first << " is ";
cur->second->write_type_to_stream(fd);
fd << "; -- imported" << endl;
cur->second->write_typedef_to_stream(fd, cur->first);
}
for (map<perm_string,const VType*>::const_iterator cur = cur_types_.begin()
; cur != cur_types_.end() ; ++cur) {
// Do not include global types in types dump
if (is_global_type(cur->first))
continue;
if(!dynamic_cast<const VTypeDef*>(cur->second))
fd << "sub";
fd << "type " << cur->first << " is ";
cur->second->write_type_to_stream(fd);
fd << ";" << endl;
cur->second->write_typedef_to_stream(fd, cur->first);
}
for (map<perm_string,struct const_t*>::const_iterator cur = cur_constants_.begin()
@ -134,10 +116,15 @@ void Package::write_to_stream(ostream&fd) const
fd << ";" << endl;
}
for (map<perm_string,SubprogramHeader*>::const_iterator cur = cur_subprograms_.begin()
for (map<perm_string,SubHeaderList>::const_iterator cur = cur_subprograms_.begin()
; cur != cur_subprograms_.end() ; ++cur) {
cur->second->write_to_stream(fd);
fd << ";" << endl;
const SubHeaderList& subp_list = cur->second;
for(SubHeaderList::const_iterator it = subp_list.begin();
it != subp_list.end(); ++it) {
(*it)->write_to_stream(fd);
fd << ";" << endl;
}
}
for (map<perm_string,ComponentBase*>::const_iterator cur = old_components_.begin()
@ -154,14 +141,20 @@ void Package::write_to_stream(ostream&fd) const
fd << "end package " << name_ << ";" << endl;
fd << "package body " << name_ << " is" << endl;
for (map<perm_string,SubprogramHeader*>::const_iterator cur = cur_subprograms_.begin()
for (map<perm_string,SubHeaderList>::const_iterator cur = cur_subprograms_.begin()
; cur != cur_subprograms_.end() ; ++cur) {
SubprogramHeader*subp = cur->second;
if(subp->body()) {
subp->write_to_stream(fd);
fd << " is" << endl;
subp->body()->write_to_stream(fd);
const SubHeaderList& subp_list = cur->second;
for(SubHeaderList::const_iterator it = subp_list.begin();
it != subp_list.end(); ++it) {
const SubprogramHeader*subp = *it;
if(subp->body()) {
subp->write_to_stream(fd);
fd << " is" << endl;
subp->body()->write_to_stream(fd);
}
}
}
}
fd << "end " << name_ << ";" << endl;
}

View File

@ -36,8 +36,6 @@ class Package : public Scope, public LineInfo {
perm_string name() const { return name_; }
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

@ -20,8 +20,9 @@
# include "package.h"
# include "subprogram.h"
# include <iostream>
# include "ivl_assert.h"
# include <iostream>
# include <list>
using namespace std;
@ -64,14 +65,22 @@ int Package::emit_package(ostream&fd) const
//}
fd << "package \\" << name() << " ;" << endl;
for (map<perm_string,SubprogramHeader*>::const_iterator cur = cur_subprograms_.begin()
for (map<perm_string,SubHeaderList>::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())
errors += cur->second->emit_package(fd);
else
fd << "/* function " << cur->second->name() <<
" has to be instantiated, skipping */" << endl;
const SubHeaderList& subp_list = cur->second;
for(SubHeaderList::const_iterator it = subp_list.begin();
it != subp_list.end(); ++it) {
SubprogramHeader*header = *it;
// Do not emit unbounded functions, we will just need fixed instances later
if(!header->unbounded())
errors += header->emit_package(fd);
else
fd << "/* function " << header->name()
<< " has to be instantiated, skipping */" << endl;
}
}
fd << "endpackage /* " << name() << " */" << endl;

View File

@ -7,7 +7,7 @@
%{
/*
* Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2012-2014 / Stephen Williams (steve@icarus.com),
* Copyright CERN 2012-2016 / Stephen Williams (steve@icarus.com),
* @author Maciej Suminski (maciej.suminski@cern.ch)
*
* This source code is free software; you can redistribute it
@ -86,6 +86,7 @@ extern int yylex(union YYSTYPE*yylvalp,YYLTYPE*yyllocp,yyscan_t yyscanner);
static ActiveScope*active_scope = new ActiveScope;
static stack<ActiveScope*> scope_stack;
static SubprogramHeader*active_sub = NULL;
static ActiveScope*arc_scope = NULL;
/*
* When a scope boundary starts, call the push_scope function to push
@ -318,6 +319,7 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
%type <arch_statement> concurrent_statement component_instantiation_statement
%type <arch_statement> concurrent_conditional_signal_assignment
%type <arch_statement> concurrent_signal_assignment_statement concurrent_simple_signal_assignment
%type <arch_statement> concurrent_assertion_statement
%type <arch_statement> for_generate_statement generate_statement if_generate_statement
%type <arch_statement> process_statement selected_signal_assignment
%type <arch_statement_list> architecture_statement_part generate_statement_body
@ -330,7 +332,7 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
%type <expr> expression factor primary relation
%type <expr> expression_logical expression_logical_and expression_logical_or
%type <expr> expression_logical_xnor expression_logical_xor
%type <expr> name prefix selected_name
%type <expr> name prefix selected_name indexed_name
%type <expr> shift_expression signal_declaration_assign_opt
%type <expr> simple_expression simple_expression_2 term
%type <expr> variable_declaration_assign_opt waveform_element interface_element_expression
@ -352,7 +354,7 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
%type <record_elements> element_declaration element_declaration_list
%type <text> architecture_body_start package_declaration_start
%type <text> package_body_start
%type <text> package_body_start process_start
%type <text> identifier_opt identifier_colon_opt logical_name suffix instantiated_unit
%type <name_list> logical_name_list identifier_list
@ -376,7 +378,7 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
%type <elsif_list> if_statement_elsif_list if_statement_elsif_list_opt
%type <exp_options> else_when_waveform selected_waveform
%type <exp_options_list> else_when_waveforms selected_waveform_list
%type <exp_options_list> else_when_waveforms else_when_waveforms_opt selected_waveform_list
%type <subprogram> function_specification procedure_specification
%type <subprogram> subprogram_specification subprogram_body_start
@ -411,6 +413,8 @@ architecture_body
delete[]$3;
delete $8;
pop_scope();
assert(arc_scope);
arc_scope = NULL;
if ($11) delete[]$11;
}
;
@ -419,6 +423,8 @@ architecture_body_start
: K_architecture IDENTIFIER
{ $$ = $2;
push_scope();
assert(!arc_scope);
arc_scope = active_scope;
}
;
/*
@ -532,7 +538,7 @@ block_declarative_item
{ /* Save the signal declaration in the block_signals map. */
for (std::list<perm_string>::iterator cur = $2->begin()
; cur != $2->end() ; ++cur) {
Signal*sig = new Signal(*cur, $4, $5);
Signal*sig = new Signal(*cur, $4, $5 ? $5->clone() : 0);
FILE_NAME(sig, @1);
active_scope->bind_name(*cur, sig);
}
@ -547,6 +553,8 @@ block_declarative_item
| subprogram_body
| subtype_declaration
| type_declaration
| use_clause_lib
@ -757,32 +765,50 @@ composite_type_definition
| K_array '(' index_subtype_definition_list ')' K_of subtype_indication
{ std::list<ExpRange*> r;
// NULL boundaries indicate unbounded array type
r.push_back(new ExpRange(NULL, NULL, ExpRange::DOWNTO));
VTypeArray*tmp = new VTypeArray($6, &r);
$$ = tmp;
ExpRange*tmp = new ExpRange(NULL, NULL, ExpRange::DOWNTO);
r.push_back(tmp);
FILE_NAME(tmp, @1);
VTypeArray*arr = new VTypeArray($6, &r);
$$ = arr;
}
| record_type_definition
{ $$ = $1; }
;
concurrent_assertion_statement
: assertion_statement
{
/* See more explanations at IEEE 1076-2008 P11.5 */
std::list<SequentialStmt*> stmts;
stmts.push_back($1);
stmts.push_back(new WaitStmt(WaitStmt::FINAL, NULL));
push_scope();
ProcessStatement*tmp = new ProcessStatement(empty_perm_string, *active_scope,
NULL, &stmts);
pop_scope();
FILE_NAME(tmp, @1);
$$ = tmp;
}
;
/* The when...else..when...else syntax is not a general expression
in VHDL but a specific sort of assignment statement model. We
create Expression objects for it, but the parser will only
recognize it it in specific situations. */
concurrent_conditional_signal_assignment /* IEEE 1076-2008 P11.6 */
: name LEQ waveform K_when expression else_when_waveforms ';'
{ ExpConditional*tmp = new ExpConditional($5, $3, $6);
FILE_NAME(tmp, @3);
delete $3;
delete $6;
: name LEQ waveform K_when expression else_when_waveforms_opt ';'
{ std::list<ExpConditional::case_t*>*options;
options = $6 ? $6 : new std::list<ExpConditional::case_t*>;
options->push_front(new ExpConditional::case_t($5, $3));
ExpName*name = dynamic_cast<ExpName*> ($1);
assert(name);
SignalAssignment*tmpa = new SignalAssignment(name, tmp);
FILE_NAME(tmpa, @1);
ExpName*name = dynamic_cast<ExpName*>($1);
assert(name);
CondSignalAssignment*tmp = new CondSignalAssignment(name, *options);
$$ = tmpa;
FILE_NAME(tmp, @1);
delete options;
$$ = tmp;
}
/* Error recovery rules. */
@ -826,6 +852,12 @@ else_when_waveforms
}
;
else_when_waveforms_opt
: else_when_waveforms { $$ = $1; }
| { $$ = 0; }
;
else_when_waveform
: K_else waveform K_when expression
{ ExpConditional::case_t*tmp = new ExpConditional::case_t($4, $2);
@ -875,6 +907,7 @@ concurrent_signal_assignment_statement /* IEEE 1076-2008 P11.6 */
concurrent_statement
: component_instantiation_statement
| concurrent_signal_assignment_statement
| concurrent_assertion_statement
| generate_statement
| process_statement
;
@ -1126,6 +1159,8 @@ expression_list
expression
: expression_logical
{ $$ = $1; }
| range
{ $$ = $1; }
;
/*
@ -1263,17 +1298,19 @@ file_declaration
std::list<Expression*> params;
// add file_open() call in 'initial' block
params.push_back(new ExpName(*cur));
params.push_back(new ExpScopedName(active_scope->peek_name(), new ExpName(*cur)));
params.push_back($5->filename()->clone());
params.push_back($5->kind()->clone());
ProcedureCall*fopen_call = new ProcedureCall(perm_string::literal("file_open"), &params);
active_scope->add_initializer(fopen_call);
ProcedureCall*fopen_call = new ProcedureCall(
perm_string::literal("file_open"), &params);
arc_scope->add_initializer(fopen_call);
// add file_close() call in 'final' block
params.clear();
params.push_back(new ExpName(*cur));
ProcedureCall*fclose_call = new ProcedureCall(perm_string::literal("file_close"), &params);
active_scope->add_finalizer(fclose_call);
params.push_back(new ExpScopedName(active_scope->peek_name(), new ExpName(*cur)));
ProcedureCall*fclose_call = new ProcedureCall(
perm_string::literal("file_close"), &params);
arc_scope->add_finalizer(fclose_call);
delete $5;
}
@ -1292,6 +1329,7 @@ file_open_information
{
ExpName*mode = new ExpName(lex_strings.make($2));
delete[]$2;
FILE_NAME(mode, @1);
$$ = new file_open_info_t(new ExpString($4), mode);
}
| K_is STRING_LITERAL
@ -1660,7 +1698,6 @@ loop_statement
BasicLoopStatement* tmp = new BasicLoopStatement(loop_name, $3);
FILE_NAME(tmp, @2);
sorrymsg(@1, "Loop statements are not supported.\n");
$$ = tmp;
};
@ -1674,7 +1711,17 @@ mode_opt : mode {$$ = $1;} | {$$ = PORT_NONE;} ;
name /* IEEE 1076-2008 P8.1 */
: IDENTIFIER /* simple_name (IEEE 1076-2008 P8.2) */
{ Expression*tmp = new ExpName(lex_strings.make($1));
{ Expression*tmp;
/* Check if the IDENTIFIER is one of CHARACTER enums (LF, CR, etc.) */
tmp = parse_char_enums($1);
if(!tmp) {
perm_string name = lex_strings.make($1);
/* There are functions that have the same name types, e.g. integer */
if(!active_scope->find_subprogram(name).empty() && !parse_type_by_name(name))
tmp = new ExpFunc(name);
else
tmp = new ExpName(name);
}
FILE_NAME(tmp, @1);
delete[]$1;
$$ = tmp;
@ -1683,37 +1730,39 @@ name /* IEEE 1076-2008 P8.1 */
| selected_name
{ $$ = $1; }
| indexed_name
{ $$ = $1; }
| selected_name '(' expression_list ')'
{
ExpName*name = dynamic_cast<ExpName*>($1);
assert(name);
name->add_index($3);
delete $3; // contents of the list is moved to the selected_name
}
;
indexed_name
/* Note that this rule can match array element selects and various
function calls. The only way we can tell the difference is from
left context, namely whether the name is a type name or function
name. If none of the above, treat it as a array element select. */
| IDENTIFIER argument_list
{ perm_string name = lex_strings.make($1);
delete[]$1;
if (active_scope->is_vector_name(name) || is_subprogram_param(name)) {
ExpName*tmp = new ExpName(name, $2);
$$ = tmp;
} else {
ExpFunc*tmp = new ExpFunc(name, $2);
$$ = tmp;
}
FILE_NAME($$, @1);
: IDENTIFIER '(' expression_list ')'
{ Expression*tmp;
perm_string name = lex_strings.make($1);
delete[]$1;
if (active_scope->is_vector_name(name) || is_subprogram_param(name))
tmp = new ExpName(name, $3);
else
tmp = new ExpFunc(name, $3);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| IDENTIFIER '(' range ')'
{ ExpName*tmp = new ExpName(lex_strings.make($1), $3->msb(), $3->lsb());
FILE_NAME(tmp, @1);
delete[]$1;
$$ = tmp;
}
| selected_name '(' range ')'
{ ExpName*tmp = dynamic_cast<ExpName*> ($1);
tmp->set_range($3->msb(), $3->lsb());
$$ = tmp;
}
| selected_name '(' expression ')'
{ ExpName*tmp = dynamic_cast<ExpName*> ($1);
tmp->set_range($3, NULL);
$$ = tmp;
| indexed_name '(' expression_list ')'
{ ExpName*name = dynamic_cast<ExpName*>($1);
assert(name);
name->add_index($3);
$$ = $1;
}
;
@ -1887,7 +1936,7 @@ primary
| name '\'' IDENTIFIER argument_list_opt
{ ExpAttribute*tmp = NULL;
perm_string attr = lex_strings.make($3);
ExpName*base = dynamic_cast<ExpName*>($1);
ExpName*base = dynamic_cast<ExpName*>($1);
const VType*type = parse_type_by_name(base->peek_name());
if(type) {
@ -1896,7 +1945,7 @@ primary
tmp = new ExpObjAttribute(base, attr, $4);
}
FILE_NAME(tmp, @3);
FILE_NAME(tmp, @1);
delete[]$3;
$$ = tmp;
}
@ -1913,8 +1962,8 @@ primary
}
| REAL_LITERAL
{ ExpReal*tmp = new ExpReal($1);
FILE_NAME(tmp, @1);
$$ = tmp;
FILE_NAME(tmp, @1);
$$ = tmp;
}
| STRING_LITERAL
{ ExpString*tmp = new ExpString($1);
@ -1987,18 +2036,21 @@ procedure_call
: IDENTIFIER ';'
{
ProcedureCall* tmp = new ProcedureCall(lex_strings.make($1));
FILE_NAME(tmp, @1);
delete[] $1;
$$ = tmp;
}
| IDENTIFIER '(' association_list ')' ';'
{
ProcedureCall* tmp = new ProcedureCall(lex_strings.make($1), $3);
FILE_NAME(tmp, @1);
delete[] $1;
$$ = tmp;
}
| IDENTIFIER argument_list ';'
{
ProcedureCall* tmp = new ProcedureCall(lex_strings.make($1), $2);
FILE_NAME(tmp, @1);
delete[] $1;
delete $2; // parameters are copied in this variant
$$ = tmp;
@ -2045,33 +2097,40 @@ process_declarative_part_opt
|
;
process_statement
process_start
: identifier_colon_opt K_postponed_opt K_process
process_sensitivity_list_opt K_is_opt
{ push_scope();
$$ = $1;
}
;
process_statement
: process_start process_sensitivity_list_opt K_is_opt
process_declarative_part_opt
K_begin sequence_of_statements
K_end K_postponed_opt K_process identifier_opt ';'
{ perm_string iname = $1? lex_strings.make($1) : perm_string();
{ perm_string iname = $1? lex_strings.make($1) : empty_perm_string;
if ($1) delete[]$1;
if ($12) {
if ($10) {
if (iname.nil()) {
errormsg(@12, "Process end name %s for un-named processes.\n", $12);
} else if (iname != $12) {
errormsg(@12, "Process name %s does not match opening name %s.\n",
$12, $1);
errormsg(@10, "Process end name %s for un-named processes.\n", $10);
} else if (iname != $10) {
errormsg(@10, "Process name %s does not match opening name %s.\n",
$10, $1);
}
delete[]$12;
delete[]$10;
}
ProcessStatement*tmp = new ProcessStatement(iname, $4, $8);
ProcessStatement*tmp = new ProcessStatement(iname, *active_scope, $2, $6);
arc_scope->bind_scope(tmp->peek_name(), tmp);
pop_scope();
FILE_NAME(tmp, @3);
delete $4;
delete $8;
delete $2;
delete $6;
$$ = tmp;
}
| identifier_colon_opt K_postponed_opt K_process
process_sensitivity_list_opt K_is_opt
| process_start process_sensitivity_list_opt K_is_opt
process_declarative_part_opt
K_begin error
K_end K_postponed_opt K_process identifier_opt ';'
@ -2113,6 +2172,7 @@ process_sensitivity_list
range
: simple_expression direction simple_expression
{ ExpRange* tmp = new ExpRange($1, $3, $2);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| name '\'' K_range
@ -2121,6 +2181,7 @@ range
ExpName*name = NULL;
if((name = dynamic_cast<ExpName*>($1))) {
tmp = new ExpRange(name, false);
FILE_NAME(tmp, @1);
} else {
errormsg(@1, "'range attribute can be used with named expressions only");
}
@ -2132,6 +2193,7 @@ range
ExpName*name = NULL;
if((name = dynamic_cast<ExpName*>($1))) {
tmp = new ExpRange(name, true);
FILE_NAME(tmp, @1);
} else {
errormsg(@1, "'reverse_range attribute can be used with named expressions only");
}
@ -2475,6 +2537,7 @@ simple_expression_2
tmp = new ExpArithmetic(item.op, tmp, item.term);
}
delete lst;
FILE_NAME(tmp, @1);
$$ = tmp;
}
;
@ -2535,12 +2598,10 @@ subprogram_body /* IEEE 1076-2008 P4.3 */
K_begin subprogram_statement_part K_end
subprogram_kind_opt identifier_opt ';'
{ SubprogramHeader*prog = $1;
SubprogramHeader*tmp = active_scope->recall_subprogram(prog->name());
if (tmp && prog->compare_specification(tmp)) {
SubprogramHeader*tmp = active_scope->recall_subprogram(prog);
if (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());
}
SubprogramBody*body = new SubprogramBody();
@ -2548,7 +2609,7 @@ subprogram_body /* IEEE 1076-2008 P4.3 */
body->set_statements($4);
prog->set_body(body);
active_scope->bind_name(prog->name(), prog);
active_scope->bind_subprogram(prog->name(), prog);
active_sub = NULL;
}
@ -2566,7 +2627,7 @@ subprogram_body /* IEEE 1076-2008 P4.3 */
subprogram_declaration
: subprogram_specification ';'
{ if ($1) active_scope->bind_name($1->name(), $1); }
{ if ($1) active_scope->bind_subprogram($1->name(), $1); }
;
subprogram_declarative_item /* IEEE 1079-2008 P4.3 */
@ -2607,12 +2668,21 @@ 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 {
active_scope->bind_name(name, $4);
VTypeDef*tmp;
map<perm_string,VTypeDef*>::iterator cur = active_scope->incomplete_types.find(name);
if (cur == active_scope->incomplete_types.end()) {
tmp = new VSubTypeDef(name, $4);
active_scope->bind_name(name, tmp);
} else {
tmp = cur->second;
tmp->set_definition($4);
active_scope->incomplete_types.erase(cur);
}
}
delete[]$2;
}
;
@ -2697,9 +2767,6 @@ type_declaration
tmp->set_definition($4);
active_scope->incomplete_types.erase(cur);
}
if(const VTypeEnum*enum_type = dynamic_cast<const VTypeEnum*>($4)) {
active_scope->use_enum(enum_type);
}
}
delete[]$2;
}
@ -2724,6 +2791,7 @@ type_declaration
type_definition
: '(' enumeration_literal_list ')'
{ VTypeEnum*tmp = new VTypeEnum($2);
active_scope->use_enum(tmp);
delete $2;
$$ = tmp;
}
@ -2821,6 +2889,11 @@ wait_statement
FILE_NAME(tmp, @1);
$$ = tmp;
}
| K_wait ';'
{ WaitStmt*tmp = new WaitStmt(WaitStmt::FINAL, NULL);
FILE_NAME(tmp, @1);
$$ = tmp;
}
;
waveform
@ -2846,6 +2919,10 @@ waveform_elements
waveform_element
: expression
{ $$ = $1; }
| expression K_after expression
{ ExpDelay*tmp = new ExpDelay($1, $3);
FILE_NAME(tmp, @1);
$$ = tmp; }
| K_null
{ $$ = 0; }
;

View File

@ -29,6 +29,7 @@
# include "compiler.h"
# include <iostream>
# include <cassert>
# include <cstring>
using namespace std;
@ -153,3 +154,14 @@ const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name,
return subtype;
}
ExpString*parse_char_enums(const char*str)
{
if(!strcasecmp(str, "LF"))
return new ExpString("\\n");
if(!strcasecmp(str, "CR"))
return new ExpString("\\r");
return NULL;
}

View File

@ -27,6 +27,7 @@ class Architecture;
class Expression;
class Package;
class ExpRange;
class ExpString;
class ScopeBase;
class VType;
@ -63,4 +64,11 @@ 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);
/*
* Converts CHARACTER enums to an ExpString* if applicable.
* See the standard VHDL library (package STANDARD) or VHDL-2008/16.3
* for more details).
*/
extern ExpString*parse_char_enums(const char*str);
#endif /* IVL_parse_misc_H */

View File

@ -24,56 +24,30 @@
# include "entity.h"
# include "std_funcs.h"
# include "std_types.h"
# include "compiler.h"
# include <algorithm>
# include <iostream>
# include <iterator>
# include <cstdio>
# include <cstring>
# include <cassert>
# include <StringHeap.h>
using namespace std;
/*
* If the merge_flag is passed in, then the new scope is a merge of
* the parent scopes. This brings in all of the parent scopes into the
* "old_*_" variables. This clears up the "new_*_" variables to
* accumulate new scope values.
*/
static int scope_counter = 0;
ScopeBase::ScopeBase(const ActiveScope&ref)
: use_constants_(ref.use_constants_), cur_constants_(ref.cur_constants_)
: old_signals_(ref.old_signals_), new_signals_(ref.new_signals_),
old_variables_(ref.old_variables_), new_variables_(ref.new_variables_),
old_components_(ref.old_components_), new_components_(ref.new_components_),
use_types_(ref.use_types_), cur_types_(ref.cur_types_),
use_constants_(ref.use_constants_), cur_constants_(ref.cur_constants_),
use_subprograms_(ref.use_subprograms_), cur_subprograms_(ref.cur_subprograms_),
scopes_(ref.scopes_), use_enums_(ref.use_enums_),
initializers_(ref.initializers_), finalizers_(ref.finalizers_),
name_(ref.name_)
{
merge(ref.old_signals_.begin(), ref.old_signals_.end(),
ref.new_signals_.begin(), ref.new_signals_.end(),
insert_iterator<map<perm_string, Signal*> >(
old_signals_, old_signals_.end())
);
merge(ref.old_variables_.begin(), ref.old_variables_.end(),
ref.new_variables_.begin(), ref.new_variables_.end(),
insert_iterator<map<perm_string, Variable*> >(
old_variables_, old_variables_.end())
);
merge(ref.old_components_.begin(), ref.old_components_.end(),
ref.new_components_.begin(), ref.new_components_.end(),
insert_iterator<map<perm_string, ComponentBase*> >(
old_components_, old_components_.end())
);
use_types_ = ref.use_types_;
cur_types_ = ref.cur_types_;
use_subprograms_ = ref.use_subprograms_;
cur_subprograms_ = ref.cur_subprograms_;
use_enums_ = ref.use_enums_;
initializers_ = ref.initializers_;
finalizers_ = ref.finalizers_;
// This constructor is invoked when the parser is finished with
// 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,SubprogramHeader*>::iterator cur = cur_subprograms_.begin()
; cur != cur_subprograms_.end(); ++cur) {
cur->second->set_parent(this);
}
}
ScopeBase::~ScopeBase()
@ -94,7 +68,20 @@ void ScopeBase::cleanup()
delete_all(new_components_);
delete_all(cur_types_);
delete_all(cur_constants_);
delete_all(cur_subprograms_);
for (map<perm_string,SubHeaderList>::iterator cur = cur_subprograms_.begin()
; cur != cur_subprograms_.end() ; ++cur) {
delete_all(cur->second);
}
}
ScopeBase*ScopeBase::find_scope(perm_string name) const
{
map<perm_string, ScopeBase*>::const_iterator it = scopes_.find(name);
if(it != scopes_.end())
return it->second;
return NULL;
}
const VType*ScopeBase::find_type(perm_string by_name)
@ -157,32 +144,42 @@ const InterfacePort* ScopeBase::find_param(perm_string) const
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,SubHeaderList>::const_iterator cur = use_subprograms_.begin();
cur != use_subprograms_.end(); ++cur) {
const SubHeaderList& subp_list = cur->second;
for(SubHeaderList::const_iterator it = subp_list.begin();
it != subp_list.end(); ++it) {
if(const InterfacePort*port = (*it)->find_param(by_name))
return port;
}
}
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;
for(map<perm_string,SubHeaderList>::const_iterator cur = cur_subprograms_.begin();
cur != cur_subprograms_.end(); ++cur) {
const SubHeaderList& subp_list = cur->second;
for(SubHeaderList::const_iterator it = subp_list.begin();
it != subp_list.end(); ++it) {
if(const InterfacePort*port = (*it)->find_param(by_name))
return port;
}
}
return NULL;
}
SubprogramHeader* ScopeBase::find_subprogram(perm_string name) const
SubHeaderList ScopeBase::find_subprogram(perm_string name) const
{
map<perm_string,SubprogramHeader*>::const_iterator cur;
map<perm_string,SubHeaderList>::const_iterator cur;
cur = cur_subprograms_.find(name);
if (cur != cur_subprograms_.end())
return cur->second;
return cur->second;
cur = use_subprograms_.find(name);
if (cur != use_subprograms_.end())
return cur->second;
return cur->second;
return find_std_subprogram(name);
}
@ -217,9 +214,9 @@ void ScopeBase::do_use_from(const ScopeBase*that)
old_components_[cur->first] = cur->second;
}
for (map<perm_string,SubprogramHeader*>::const_iterator cur = that->cur_subprograms_.begin()
for (map<perm_string,SubHeaderList>::const_iterator cur = that->cur_subprograms_.begin()
; cur != that->cur_subprograms_.end() ; ++ cur) {
if (cur->second == 0)
if (cur->second.empty())
continue;
use_subprograms_[cur->first] = cur->second;
}
@ -266,21 +263,89 @@ void ScopeBase::transfer_from(ScopeBase&ref, transfer_type_t what)
}
}
void ActiveScope::set_package_header(Package*pkg)
SubprogramHeader*ScopeBase::match_subprogram(perm_string name,
const list<const VType*>*params) const
{
assert(package_header_ == 0);
package_header_ = pkg;
int req_param_count = params ? params->size() : 0;
// Find all subprograms with matching name
SubHeaderList l = find_std_subprogram(name);
map<perm_string,SubHeaderList>::const_iterator cur;
cur = use_subprograms_.find(name);
if (cur != use_subprograms_.end())
copy(cur->second.begin(), cur->second.end(),
front_insert_iterator<SubHeaderList>(l));
cur = cur_subprograms_.find(name);
if(cur != cur_subprograms_.end())
copy(cur->second.begin(), cur->second.end(),
front_insert_iterator<SubHeaderList>(l));
// Find the matching one
for(SubHeaderList::iterator it = l.begin(); it != l.end(); ++it) {
SubprogramHeader*subp = *it;
if(req_param_count != subp->param_count())
continue;
// Do not check the return type here, it might depend on the arguments
if(params) {
list<const VType*>::const_iterator p = params->begin();
bool ok = true;
for(int i = 0; i < req_param_count; ++i) {
const VType*param_type = subp->peek_param_type(i);
if(*p && param_type && !param_type->type_match(*p)) {
ok = false;
break;
}
++p;
}
if(!ok)
continue; // check another function
}
// Yay, we have a match!
return subp;
}
return NULL;
}
SubprogramHeader* ActiveScope::recall_subprogram(perm_string name) const
void ScopeBase::generate_name()
{
if (SubprogramHeader*tmp = find_subprogram(name))
return tmp;
char buf[64];
if (package_header_)
return package_header_->find_subprogram(name);
// Generate a name for the scope
snprintf(buf, sizeof(buf), "__scope_%d", scope_counter++);
name_ = gen_strings.make(buf);
}
return 0;
SubprogramHeader* ActiveScope::recall_subprogram(const SubprogramHeader*subp) const
{
list<const VType*> arg_types;
SubprogramHeader*tmp;
for(int i = 0; i < subp->param_count(); ++i)
arg_types.push_back(subp->peek_param_type(i));
if ((tmp = match_subprogram(subp->name(), &arg_types))) {
assert(!tmp->body());
return tmp;
}
if (package_header_) {
tmp = package_header_->match_subprogram(subp->name(), &arg_types);
assert(!tmp || !tmp->body());
return tmp;
}
return NULL;
}
bool ActiveScope::is_vector_name(perm_string name) const
@ -301,15 +366,6 @@ bool ActiveScope::is_vector_name(perm_string name) const
return false;
}
Scope::Scope(const ActiveScope&ref)
: ScopeBase(ref)
{
}
Scope::~Scope()
{
}
ComponentBase* Scope::find_component(perm_string by_name)
{
map<perm_string,ComponentBase*>::const_iterator cur = new_components_.find(by_name);
@ -322,3 +378,37 @@ ComponentBase* Scope::find_component(perm_string by_name)
} else
return cur->second;
}
ActiveScope::ActiveScope(const ActiveScope*par)
: ScopeBase(*par), context_entity_(par->context_entity_)
{
generate_name();
// Move all the objects available in higher level scopes to use*/old* maps.
// This way we can store the new items in now empty cur*/new* maps.
merge(par->old_signals_.begin(), par->old_signals_.end(),
par->new_signals_.begin(), par->new_signals_.end(),
insert_iterator<map<perm_string, Signal*> >(
old_signals_, old_signals_.end())
);
merge(par->old_variables_.begin(), par->old_variables_.end(),
par->new_variables_.begin(), par->new_variables_.end(),
insert_iterator<map<perm_string, Variable*> >(
old_variables_, old_variables_.end())
);
merge(par->old_components_.begin(), par->old_components_.end(),
par->new_components_.begin(), par->new_components_.end(),
insert_iterator<map<perm_string, ComponentBase*> >(
old_components_, old_components_.end())
);
merge(par->use_types_.begin(), par->use_types_.end(),
par->cur_types_.begin(), par->cur_types_.end(),
insert_iterator<map<perm_string, const VType*> >(
use_types_, use_types_.end())
);
merge(par->use_subprograms_.begin(), par->use_subprograms_.end(),
par->cur_subprograms_.begin(), par->cur_subprograms_.end(),
insert_iterator<map<perm_string, SubHeaderList> >(
use_subprograms_, use_subprograms_.end())
);
}

View File

@ -36,6 +36,8 @@ class SubprogramHeader;
class VType;
class SequentialStmt;
typedef list<SubprogramHeader*> SubHeaderList;
template<typename T>
struct delete_object{
void operator()(T* item) { delete item; }
@ -53,13 +55,14 @@ class ScopeBase {
explicit ScopeBase(const ActiveScope&ref);
virtual ~ScopeBase() =0;
ScopeBase* find_scope(perm_string name) const;
const VType* find_type(perm_string by_name);
virtual bool find_constant(perm_string by_name, const VType*&typ, Expression*&exp) const;
Signal* find_signal(perm_string by_name) const;
Variable* find_variable(perm_string by_name) const;
virtual Variable* find_variable(perm_string by_name) const;
virtual const InterfacePort* find_param(perm_string by_name) const;
const InterfacePort* find_param_all(perm_string by_name) const;
SubprogramHeader* find_subprogram(perm_string by_name) const;
SubHeaderList 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;
@ -70,10 +73,10 @@ class ScopeBase {
void transfer_from(ScopeBase&ref, transfer_type_t what = ALL);
inline void bind_subprogram(perm_string name, SubprogramHeader*obj)
{ map<perm_string, SubprogramHeader*>::iterator it;
{ map<perm_string, SubHeaderList>::iterator it;
if((it = use_subprograms_.find(name)) != use_subprograms_.end() )
use_subprograms_.erase(it);
cur_subprograms_[name] = obj;
it->second.remove(obj);
cur_subprograms_[name].push_back(obj);
}
// Adds a statement to implicit initializers list
@ -92,6 +95,17 @@ class ScopeBase {
void dump_scope(ostream&out) const;
// Looks for a subprogram with specified name and parameter types.
SubprogramHeader*match_subprogram(perm_string name,
const list<const VType*>*params) const;
perm_string peek_name() const { return name_; }
void set_package_header(Package*pkg) {
assert(package_header_ == 0);
package_header_ = pkg;
}
protected:
void cleanup();
@ -134,8 +148,10 @@ 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, SubprogramHeader*> use_subprograms_; //imported
std::map<perm_string, SubprogramHeader*> cur_subprograms_; //current
std::map<perm_string, SubHeaderList> use_subprograms_; //imported
std::map<perm_string, SubHeaderList> cur_subprograms_; //current
std::map<perm_string, ScopeBase*> scopes_;
std::list<const VTypeEnum*> use_enums_;
@ -146,20 +162,30 @@ class ScopeBase {
std::list<SequentialStmt*> finalizers_;
void do_use_from(const ScopeBase*that);
// If this is a package body, then there is a Package header
// already declared.
Package*package_header_;
// Generates an unique name for the scope
void generate_name();
private:
perm_string name_;
};
class Scope : public ScopeBase {
public:
explicit Scope(const ActiveScope&ref);
~Scope();
explicit Scope(const ActiveScope&ref) : ScopeBase(ref) {}
virtual ~Scope() {}
ComponentBase* find_component(perm_string by_name);
protected:
// Helper method for emitting signals in the scope.
int emit_signals(ostream&out, Entity*ent, Architecture*arc);
int emit_variables(ostream&out, Entity*ent, Architecture*arc);
int emit_signals(ostream&out, Entity*ent, ScopeBase*scope);
int emit_variables(ostream&out, Entity*ent, ScopeBase*scope);
};
/*
@ -171,13 +197,11 @@ class Scope : public ScopeBase {
class ActiveScope : public ScopeBase {
public:
ActiveScope() : package_header_(0), context_entity_(0) { }
explicit ActiveScope(ActiveScope*par) : ScopeBase(*par), package_header_(0), context_entity_(0) { }
ActiveScope() : context_entity_(0) { }
explicit ActiveScope(const ActiveScope*par);
~ActiveScope() { }
void set_package_header(Package*);
// Pull items from "that" scope into "this" scope as is
// defined by a "use" directive. The parser uses this method
// to implement the "use <pkg>::*" directive.
@ -191,7 +215,7 @@ class ActiveScope : public ScopeBase {
// Locate the subprogram by name. The subprogram body uses
// this to locate the subprogram declaration. Note that the
// subprogram may be in a package header.
SubprogramHeader* recall_subprogram(perm_string name) const;
SubprogramHeader* recall_subprogram(const SubprogramHeader*subp) 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
@ -227,6 +251,12 @@ class ActiveScope : public ScopeBase {
cur_types_[name] = t;
}
void bind_scope(perm_string name, ScopeBase*scope)
{
assert(scopes_.find(name) == scopes_.end());
scopes_[name] = scope;
}
inline void use_enum(const VTypeEnum* t)
{ use_enums_.push_back(t); }
@ -240,13 +270,6 @@ class ActiveScope : public ScopeBase {
cur_constants_[name] = new const_t(obj, val);
}
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;
}
void bind(Entity*ent)
{ context_entity_ = ent; }
@ -260,10 +283,6 @@ class ActiveScope : public ScopeBase {
std::map<perm_string,VTypeDef*> incomplete_types;
private:
// If this is a package body, then there is a Package header
// already declared.
Package*package_header_;
Entity*context_entity_;
};

View File

@ -135,6 +135,7 @@ class ReturnStmt : public SequentialStmt {
~ReturnStmt();
public:
int elaborate(Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*entity, ScopeBase*scope);
void write_to_stream(std::ostream&fd);
void dump(ostream&out, int indent) const;
@ -273,6 +274,8 @@ class BasicLoopStatement : public LoopStatement {
~BasicLoopStatement();
int elaborate(Entity*ent, ScopeBase*scope);
int emit(ostream&out, Entity*ent, ScopeBase*scope);
void write_to_stream(std::ostream&fd);
void dump(ostream&out, int indent) const;
};
@ -330,7 +333,7 @@ class WaitForStmt : public SequentialStmt {
class WaitStmt : public SequentialStmt {
public:
typedef enum { ON, UNTIL } wait_type_t;
typedef enum { ON, UNTIL, FINAL } wait_type_t;
WaitStmt(wait_type_t type, Expression*expression);
void dump(ostream&out, int indent) const;
@ -338,6 +341,8 @@ class WaitStmt : public SequentialStmt {
int emit(ostream&out, Entity*entity, ScopeBase*scope);
void write_to_stream(std::ostream&fd);
inline wait_type_t type() const { return type_; }
private:
wait_type_t type_;
Expression*expr_;

View File

@ -199,6 +199,16 @@ void WaitForStmt::dump(ostream&out, int indent) const
void WaitStmt::dump(ostream&out, int indent) const
{
out << setw(indent) << "" << "WaitStmt at file=" << get_fileline() << endl;
out << setw(indent+3) << "" << "expression: ";
expr_->dump(out, indent+3);
out << setw(indent+3) << "type = ";
switch(type_) {
case ON: out << "ON" << endl; break;
case UNTIL: out << "UNTIL" << endl; break;
case FINAL: out << "FINAL" << endl; break;
}
if(type_ != FINAL) {
out << setw(indent+3) << "" << "expression: ";
expr_->dump(out, indent+3);
}
}

View File

@ -99,7 +99,7 @@ int IfSequential::elaborate(Entity*ent, ScopeBase*scope)
{
int errors = 0;
errors += cond_->elaborate_expr(ent, scope, 0);
errors += cond_->elaborate_expr(ent, scope, &type_BOOLEAN);
for (list<SequentialStmt*>::iterator cur = if_.begin()
; cur != if_.end() ; ++cur) {
@ -123,7 +123,7 @@ int IfSequential::Elsif::elaborate(Entity*ent, ScopeBase*scope)
{
int errors = 0;
errors += cond_->elaborate_expr(ent, scope, 0);
errors += cond_->elaborate_expr(ent, scope, &type_BOOLEAN);
for (list<SequentialStmt*>::iterator cur = if_.begin()
; cur != if_.end() ; ++cur) {
@ -133,6 +133,22 @@ int IfSequential::Elsif::elaborate(Entity*ent, ScopeBase*scope)
return errors;
}
int ReturnStmt::elaborate(Entity*ent, ScopeBase*scope)
{
const VType*ltype = NULL;
// Try to determine the expression type by
// looking up the function return type.
const SubprogramBody*subp = dynamic_cast<const SubprogramBody*>(scope);
if(subp) {
if(const SubprogramHeader*header = subp->header()) {
ltype = header->peek_return_type();
}
}
return val_->elaborate_expr(ent, scope, ltype);
}
int SignalSeqAssignment::elaborate(Entity*ent, ScopeBase*scope)
{
int errors = 0;
@ -162,19 +178,36 @@ int ProcedureCall::elaborate(Entity*ent, ScopeBase*scope)
{
int errors = 0;
def_ = scope->find_subprogram(name_);
assert(!def_); // do not elaborate twice
// Create a list of argument types to find a matching subprogram
list<const VType*> arg_types;
if(param_list_) {
for(list<named_expr_t*>::iterator it = param_list_->begin();
it != param_list_->end(); ++it) {
named_expr_t* e = *it;
arg_types.push_back(e->expr()->probe_type(ent, scope));
}
}
def_ = scope->match_subprogram(name_, &arg_types);
if(!def_)
def_ = library_find_subprogram(name_);
def_ = library_match_subprogram(name_, &arg_types);
assert(def_);
if(!def_) {
cerr << get_fileline() << ": error: could not find procedure ";
emit_subprogram_sig(cerr, name_, arg_types);
cerr << endl;
return 1;
}
// Elaborate arguments
size_t idx = 0;
if(param_list_) {
for(list<named_expr_t*>::iterator cur = param_list_->begin()
; cur != param_list_->end() ; ++cur) {
errors += elaborate_argument((*cur)->expr(), def_, idx, ent, scope);
errors += def_->elaborate_argument((*cur)->expr(), idx, ent, scope);
++idx;
}
}
@ -212,9 +245,9 @@ int WhileLoopStatement::elaborate(Entity*ent, ScopeBase*scope)
return errors;
}
int BasicLoopStatement::elaborate(Entity*, ScopeBase*)
int BasicLoopStatement::elaborate(Entity*ent, ScopeBase*scope)
{
return 0;
return elaborate_substatements(ent, scope);
}
int ReportStmt::elaborate(Entity*ent, ScopeBase*scope)
@ -232,7 +265,7 @@ int AssertStmt::elaborate(Entity*ent, ScopeBase*scope)
int WaitForStmt::elaborate(Entity*ent, ScopeBase*scope)
{
return delay_->elaborate_expr(ent, scope, 0);
return delay_->elaborate_expr(ent, scope, &primitive_TIME);
}
int WaitStmt::elaborate(Entity*ent, ScopeBase*scope)
@ -253,6 +286,8 @@ int WaitStmt::elaborate(Entity*ent, ScopeBase*scope)
// Fill the sensitivity list
expr_->visit(fill_sens_list);
} else if(type_ == FINAL) {
return 0; // nothing to be elaborated
}
return expr_->elaborate_expr(ent, scope, 0);

View File

@ -26,9 +26,11 @@
# include "package.h"
# include "compiler.h"
# include "subprogram.h"
# include "std_types.h"
# include <iostream>
# include <cstdio>
# include <typeinfo>
# include <limits>
# include <ivl_assert.h>
int SequentialStmt::emit(ostream&out, Entity*, ScopeBase*)
@ -82,7 +84,7 @@ void IfSequential::write_to_stream(std::ostream&fd)
{
fd << "if ";
cond_->write_to_stream(fd);
fd << " then " << endl;
fd << " then" << endl;
for (list<SequentialStmt*>::iterator cur = if_.begin()
; cur != if_.end() ; ++cur)
@ -210,26 +212,27 @@ void VariableSeqAssignment::write_to_stream(ostream&fd)
int ProcedureCall::emit(ostream&out, Entity*ent, ScopeBase*scope)
{
int errors = 0;
std::vector<Expression*>params;
vector<Expression*>argv;
if(!def_) {
cerr << get_fileline() << ": error: unknown procedure: " << name_ << endl;
return 1;
}
// Convert the parameter list to vector
if(param_list_) {
params.reserve(param_list_->size());
argv.reserve(param_list_->size());
for(std::list<named_expr_t*>::iterator it = param_list_->begin();
it != param_list_->end(); ++it)
params.push_back((*it)->expr());
argv.push_back((*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);
def_->emit_full_name(argv, out, ent, scope);
out << " (";
if(param_list_) {
errors += def_->emit_args(params, out, ent, scope);
}
if(param_list_)
errors += def_->emit_args(argv, out, ent, scope);
out << ");" << endl;
return errors;
@ -477,6 +480,24 @@ int ForLoopStatement::emit_runtime_(ostream&out, Entity*ent, ScopeBase*scope)
return errors;
}
int BasicLoopStatement::emit(ostream&out, Entity*ent, ScopeBase*scope)
{
int errors = 0;
out << "forever begin" << endl;
errors += emit_substatements(out, ent, scope);
out << "end" << endl;
return errors;
}
void BasicLoopStatement::write_to_stream(std::ostream&fd)
{
fd << "loop" << endl;
write_to_stream_substatements(fd);
fd << "end loop;" << endl;
}
int ReportStmt::emit(ostream&out, Entity*ent, ScopeBase*scope)
{
out << "$display(\"** ";
@ -492,8 +513,47 @@ int ReportStmt::emit(ostream&out, Entity*ent, ScopeBase*scope)
out << ": \",";
msg_->emit(out, ent, scope);
out << ",\" (" << get_fileline() << ")\");";
struct emitter : public ExprVisitor {
emitter(ostream&outp, Entity*enti, ScopeBase*scop)
: out_(outp), ent_(enti), scope_(scop),
level_lock_(numeric_limits<int>::max()) {}
void operator() (Expression*s) {
if(!dynamic_cast<ExpConcat*>(s)) {
if(level() > level_lock_)
return;
if(dynamic_cast<ExpAttribute*>(s)) {
level_lock_ = level();
} else {
level_lock_ = numeric_limits<int>::max();
}
const VType*type = s->probe_type(ent_, scope_);
if(dynamic_cast<ExpName*>(s) && type
&& type->type_match(&primitive_STRING)) {
out_ << "$sformatf(\"%s\", (";
s->emit(out_, ent_, scope_);
out_ << "))";
} else {
s->emit(out_, ent_, scope_);
}
out_ << ", ";
}
}
private:
ostream&out_;
Entity*ent_;
ScopeBase*scope_;
int level_lock_;
} emit_visitor(out, ent, scope);
msg_->visit(emit_visitor);
out << "\" (" << get_fileline() << ")\");";
if(severity_ == FAILURE)
out << "$finish();";
@ -584,6 +644,10 @@ int WaitStmt::emit(ostream&out, Entity*ent, ScopeBase*scope)
out << "wait(";
break;
case FINAL:
out << "/* final wait */" << endl;
return 0; // no expression to be emitted
}
errors += expr_->emit(out, ent, scope);
@ -602,6 +666,10 @@ void WaitStmt::write_to_stream(std::ostream&fd)
case UNTIL:
fd << "wait until ";
break;
case FINAL:
fd << "wait";
return; // no expression to be emitted
}
expr_->write_to_stream(fd);

View File

@ -1,5 +1,5 @@
/*
* Copyright CERN 2015
* Copyright CERN 2016
* @author Maciej Suminski (maciej.suminski@cern.ch)
*
* This source code is free software; you can redistribute it
@ -22,19 +22,22 @@
#include "std_types.h"
#include "scope.h"
static std::map<perm_string,SubprogramHeader*> std_subprograms;
static std::map<perm_string,SubHeaderList> std_subprograms;
static inline void register_std_subprogram(SubprogramHeader*header)
{
std_subprograms[header->name()].push_back(header);
}
// Special case: to_integer function
static class SubprogramToInteger : public SubprogramHeader {
class SubprogramToInteger : public SubprogramStdHeader {
public:
SubprogramToInteger()
: SubprogramHeader(perm_string::literal("to_integer"), NULL, &primitive_REAL) {
ports_ = new std::list<InterfacePort*>();
: SubprogramStdHeader(perm_string::literal("to_integer"), NULL, &primitive_REAL) {
ports_ = new 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;
@ -56,20 +59,18 @@ static class SubprogramToInteger : public SubprogramHeader {
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 {
class SubprogramSizeCast : public SubprogramStdHeader {
public:
explicit SubprogramSizeCast(perm_string nam)
: SubprogramHeader(nam, NULL, &primitive_STDLOGIC_VECTOR) {
ports_ = new std::list<InterfacePort*>();
ports_->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR));
explicit SubprogramSizeCast(perm_string nam, const VType*base, const VType*target)
: SubprogramStdHeader(nam, NULL, target) {
ports_ = new list<InterfacePort*>();
ports_->push_back(new InterfacePort(base));
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;
@ -90,20 +91,17 @@ static class SubprogramSizeCast : public SubprogramHeader {
return argv[0]->emit(out, ent, scope);
}
}*fn_conv_std_logic_vector, *fn_resize;
};
static class SubprogramReadWrite : public SubprogramBuiltin {
class SubprogramReadWrite : public SubprogramBuiltin {
public:
SubprogramReadWrite(perm_string nam, perm_string newnam)
: SubprogramBuiltin(nam, newnam, NULL, NULL) {
ports_ = new std::list<InterfacePort*>();
ports_->push_back(new InterfacePort(&primitive_STRING, PORT_INOUT));
ports_->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR, PORT_INOUT));
ports_->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
SubprogramReadWrite(perm_string nam, perm_string newnam, bool hex = false)
: SubprogramBuiltin(nam, newnam, NULL, NULL), hex_format_(hex) {
ports_ = new list<InterfacePort*>();
ports_->push_back(new InterfacePort(&primitive_STRING));
ports_->push_back(new InterfacePort(NULL));
}
bool is_std() const { return true; }
// Format types handled by $ivlh_read/write (see vpi/vhdl_textio.c)
enum format_t { FORMAT_STD, FORMAT_BOOL, FORMAT_TIME, FORMAT_HEX, FORMAT_STRING };
@ -118,160 +116,175 @@ static class SubprogramReadWrite : public SubprogramBuiltin {
}
const VType*arg_type = argv[1]->probe_type(ent, scope);
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(arg_type);
const VTypePrimitive*prim = dynamic_cast<const VTypePrimitive*>(arg_type);
while(const VTypeDef*tdef = dynamic_cast<const VTypeDef*>(arg_type))
arg_type = tdef->peek_definition();
// Pick the right format
if(prim && prim->type() == VTypePrimitive::TIME)
out << FORMAT_TIME;
else if(arg_type && arg_type->type_match(&type_BOOLEAN))
out << FORMAT_BOOL;
else if((arg_type && arg_type->type_match(&primitive_CHARACTER)) ||
(arr && arr->element_type() == &primitive_CHARACTER))
out << FORMAT_STRING;
else
if(hex_format_) {
out << FORMAT_HEX;
} else if(arg_type) {
if(arg_type->type_match(&primitive_TIME)) {
out << FORMAT_TIME;
} else if(arg_type->type_match(&type_BOOLEAN)) {
out << FORMAT_BOOL;
} else if(arg_type->type_match(&primitive_CHARACTER)) {
out << FORMAT_STRING;
} else {
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(arg_type);
if(arr && arr->element_type() == &primitive_CHARACTER)
out << FORMAT_STRING;
else
out << FORMAT_STD;
}
} else {
out << FORMAT_STD;
}
return errors;
}
}*fn_read, *fn_write;
static class SubprogramHexReadWrite : public SubprogramBuiltin {
public:
SubprogramHexReadWrite(perm_string nam, perm_string newnam)
: SubprogramBuiltin(nam, newnam, NULL, NULL) {
ports_ = new std::list<InterfacePort*>();
ports_->push_back(new InterfacePort(&primitive_STRING, PORT_INOUT));
ports_->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR, PORT_INOUT));
ports_->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
}
bool is_std() const { return true; }
int emit_args(const std::vector<Expression*>&argv,
std::ostream&out, Entity*ent, ScopeBase*scope) const {
int errors = 0;
for(int i = 0; i < 2; ++i) {
errors += argv[i]->emit(out, ent, scope);
out << ", ";
}
out << SubprogramReadWrite::FORMAT_HEX;
return errors;
}
}*fn_hread, *fn_hwrite;
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;
static SubprogramBuiltin*fn_file_open;
static SubprogramBuiltin*fn_file_close;
static SubprogramBuiltin*fn_endfile;
static SubprogramBuiltin*fn_readline;
static SubprogramBuiltin*fn_writeline;
private:
bool hex_format_;
};
void preload_std_funcs(void)
{
list<InterfacePort*>*args;
/* function now */
SubprogramBuiltin*fn_now = new SubprogramBuiltin(perm_string::literal("now"),
perm_string::literal("$time"), NULL, NULL);
register_std_subprogram(fn_now);
/* 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"),
args = new list<InterfacePort*>();
args->push_back(new InterfacePort(&primitive_INTEGER));
register_std_subprogram(new SubprogramBuiltin(perm_string::literal("unsigned"),
perm_string::literal("$unsigned"),
fn_unsigned_args, &primitive_UNSIGNED);
std_subprograms[fn_unsigned->name()] = fn_unsigned;
args, &primitive_UNSIGNED));
args = new list<InterfacePort*>();
args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR));
register_std_subprogram(new SubprogramBuiltin(perm_string::literal("unsigned"),
perm_string::literal("$unsigned"),
args, &primitive_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"),
args = new list<InterfacePort*>();
args->push_back(new InterfacePort(&primitive_REAL));
register_std_subprogram(new SubprogramBuiltin(perm_string::literal("integer"),
perm_string::literal("$signed"),
fn_integer_args, &primitive_INTEGER);
std_subprograms[fn_integer->name()] = fn_integer;
args, &primitive_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"),
args = new list<InterfacePort*>();
args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR));
register_std_subprogram(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;
args, &primitive_STDLOGIC_VECTOR));
/* numeric_std library
* function shift_left (arg: unsigned; count: natural) return unsigned;
* function shift_left (arg: signed; count: natural) return signed;
*/
args = new list<InterfacePort*>();
args->push_back(new InterfacePort(&primitive_UNSIGNED));
args->push_back(new InterfacePort(&primitive_NATURAL));
register_std_subprogram(new SubprogramBuiltin(perm_string::literal("shift_left"),
perm_string::literal("$ivlh_shift_left"),
args, &primitive_UNSIGNED));
args = new list<InterfacePort*>();
args->push_back(new InterfacePort(&primitive_SIGNED));
args->push_back(new InterfacePort(&primitive_NATURAL));
register_std_subprogram(new SubprogramBuiltin(perm_string::literal("shift_left"),
perm_string::literal("$ivlh_shift_left"),
args, &primitive_SIGNED));
/* numeric_std library
* function shift_right (arg: unsigned; count: natural) return unsigned;
* function shift_right (arg: signed; count: natural) return signed;
*/
args = new list<InterfacePort*>();
args->push_back(new InterfacePort(&primitive_SIGNED));
args->push_back(new InterfacePort(&primitive_NATURAL));
register_std_subprogram(new SubprogramBuiltin(perm_string::literal("shift_right"),
perm_string::literal("$ivlh_shift_right"),
args, &primitive_SIGNED));
/* function resize
*/
fn_resize = new SubprogramSizeCast(perm_string::literal("resize"));
std_subprograms[fn_resize->name()] = fn_resize;
register_std_subprogram(new SubprogramSizeCast(perm_string::literal("resize"),
&primitive_STDLOGIC_VECTOR, &primitive_STDLOGIC_VECTOR));
/* std_logic_arith library
* function conv_std_logic_vector(arg: integer; size: integer) return 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;
register_std_subprogram(new SubprogramSizeCast(perm_string::literal("conv_std_logic_vector"),
&primitive_INTEGER, &primitive_STDLOGIC_VECTOR));
/* numeric_bit library
* function to_integer (arg: unsigned) return natural;
*/
args = new list<InterfacePort*>();
args->push_back(new InterfacePort(&primitive_UNSIGNED));
register_std_subprogram(new SubprogramBuiltin(perm_string::literal("to_integer"),
perm_string::literal("$unsigned"),
args, &primitive_NATURAL));
/* numeric_bit library
* function to_integer (arg: signed) return integer;
*/
fn_to_integer = new SubprogramToInteger();
std_subprograms[fn_to_integer->name()] = fn_to_integer;
args = new list<InterfacePort*>();
args->push_back(new InterfacePort(&primitive_SIGNED));
register_std_subprogram(new SubprogramBuiltin(perm_string::literal("to_integer"),
perm_string::literal("$signed"),
args, &primitive_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"),
args = new list<InterfacePort*>();
args->push_back(new InterfacePort(&primitive_STDLOGIC));
register_std_subprogram(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;
args, &type_BOOLEAN));
/* 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"),
args = new list<InterfacePort*>();
args->push_back(new InterfacePort(&primitive_STDLOGIC));
register_std_subprogram(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;
args, &type_BOOLEAN));
/* 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"),
args = new list<InterfacePort*>();
args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR));
register_std_subprogram(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;
args, &primitive_STDLOGIC));
/* 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"),
args = new list<InterfacePort*>();
args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR));
register_std_subprogram(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;
args, &primitive_STDLOGIC));
/* fixed_pkg library
* function to_unsigned (
@ -279,108 +292,131 @@ void preload_std_funcs(void)
* 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"),
args = new list<InterfacePort*>();
args->push_back(new InterfacePort(&primitive_REAL));
args->push_back(new InterfacePort(&primitive_NATURAL));
register_std_subprogram(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;
args, &primitive_UNSIGNED));
/* numeric_std library
* function to_unsigned(arg, size : natural) return unsigned;
*/
args = new list<InterfacePort*>();
args->push_back(new InterfacePort(&primitive_NATURAL));
args->push_back(new InterfacePort(&primitive_NATURAL));
register_std_subprogram(new SubprogramBuiltin(perm_string::literal("to_unsigned"),
perm_string::literal("$ivlh_to_unsigned"),
args, &primitive_UNSIGNED));
/* numeric_std library
* function to_unsigned(arg : std_logic_vector, size : natural) return unsigned;
*/
args = new list<InterfacePort*>();
args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR));
args->push_back(new InterfacePort(&primitive_NATURAL));
register_std_subprogram(new SubprogramBuiltin(perm_string::literal("to_unsigned"),
perm_string::literal("$ivlh_to_unsigned"),
args, &primitive_UNSIGNED));
/* procedure file_open (file f: text; filename: in string, file_open_kind: in mode);
*/
std::list<InterfacePort*>*fn_file_open_args = new std::list<InterfacePort*>();
fn_file_open_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
fn_file_open_args->push_back(new InterfacePort(&primitive_STRING, PORT_IN));
fn_file_open_args->push_back(new InterfacePort(&type_FILE_OPEN_KIND, PORT_IN));
fn_file_open = new SubprogramBuiltin(perm_string::literal("file_open"),
args = new list<InterfacePort*>();
args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
args->push_back(new InterfacePort(&primitive_STRING, PORT_IN));
args->push_back(new InterfacePort(&type_FILE_OPEN_KIND, PORT_IN));
register_std_subprogram(new SubprogramBuiltin(perm_string::literal("file_open"),
perm_string::literal("$ivlh_file_open"),
fn_file_open_args, NULL);
std_subprograms[fn_file_open->name()] = fn_file_open;
args, NULL));
/* procedure file_open (status: out file_open_status, file f: text; filename: in string, file_open_kind: in mode);
*/
args = new list<InterfacePort*>();
args->push_back(new InterfacePort(&type_FILE_OPEN_STATUS, PORT_OUT));
args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
args->push_back(new InterfacePort(&primitive_STRING, PORT_IN));
args->push_back(new InterfacePort(&type_FILE_OPEN_KIND, PORT_IN));
register_std_subprogram(new SubprogramBuiltin(perm_string::literal("file_open"),
perm_string::literal("$ivlh_file_open"),
args, NULL));
/* std.textio library
* procedure file_close (file f: text);
*/
std::list<InterfacePort*>*fn_file_close_args = new std::list<InterfacePort*>();
fn_file_close_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
fn_file_close = new SubprogramBuiltin(perm_string::literal("file_close"),
args = new list<InterfacePort*>();
args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
register_std_subprogram(new SubprogramBuiltin(perm_string::literal("file_close"),
perm_string::literal("$fclose"),
fn_file_close_args, NULL);
std_subprograms[fn_file_close->name()] = fn_file_close;
args, NULL));
/* std.textio library
* procedure read (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time);
*/
fn_read = new SubprogramReadWrite(perm_string::literal("read"),
perm_string::literal("$ivlh_read"));
std_subprograms[fn_read->name()] = fn_read;
register_std_subprogram(new SubprogramReadWrite(perm_string::literal("read"),
perm_string::literal("$ivlh_read")));
/* std.textio library
* procedure write (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time);
*/
fn_write = new SubprogramReadWrite(perm_string::literal("write"),
perm_string::literal("$ivlh_write"));
std_subprograms[fn_write->name()] = fn_write;
register_std_subprogram(new SubprogramReadWrite(perm_string::literal("write"),
perm_string::literal("$ivlh_write")));
/* std.textio library
* procedure hread (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time);
*/
fn_hread = new SubprogramHexReadWrite(perm_string::literal("hread"),
perm_string::literal("$ivlh_read"));
std_subprograms[fn_hread->name()] = fn_hread;
register_std_subprogram(new SubprogramReadWrite(perm_string::literal("hread"),
perm_string::literal("$ivlh_read"), true));
/* std.textio library
* procedure hwrite (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time);
*/
fn_hwrite = new SubprogramHexReadWrite(perm_string::literal("hwrite"),
perm_string::literal("$ivlh_write"));
std_subprograms[fn_hwrite->name()] = fn_hwrite;
register_std_subprogram(new SubprogramReadWrite(perm_string::literal("hwrite"),
perm_string::literal("$ivlh_write"), true));
/* std.textio library
* procedure readline (file f: text; l: inout line);
*/
std::list<InterfacePort*>*fn_readline_args = new std::list<InterfacePort*>();
fn_readline_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
fn_readline_args->push_back(new InterfacePort(&primitive_STRING, PORT_OUT));
fn_readline = new SubprogramBuiltin(perm_string::literal("readline"),
args = new list<InterfacePort*>();
args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
args->push_back(new InterfacePort(&primitive_STRING, PORT_OUT));
register_std_subprogram(new SubprogramBuiltin(perm_string::literal("readline"),
perm_string::literal("$ivlh_readline"),
fn_readline_args, NULL);
std_subprograms[fn_readline->name()] = fn_readline;
args, NULL));
/* std.textio library
* procedure writeline (file f: text; l: inout line);
*/
std::list<InterfacePort*>*fn_writeline_args = new std::list<InterfacePort*>();
fn_writeline_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
fn_writeline_args->push_back(new InterfacePort(&primitive_STRING, PORT_IN));
fn_writeline = new SubprogramBuiltin(perm_string::literal("writeline"),
args = new list<InterfacePort*>();
args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
args->push_back(new InterfacePort(&primitive_STRING, PORT_IN));
register_std_subprogram(new SubprogramBuiltin(perm_string::literal("writeline"),
perm_string::literal("$ivlh_writeline"),
fn_writeline_args, NULL);
std_subprograms[fn_writeline->name()] = fn_writeline;
args, NULL));
/* function endline (file f: text) return boolean;
*/
std::list<InterfacePort*>*fn_endfile_args = new std::list<InterfacePort*>();
fn_endfile_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
fn_endfile = new SubprogramBuiltin(perm_string::literal("endfile"),
args = new list<InterfacePort*>();
args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
register_std_subprogram(new SubprogramBuiltin(perm_string::literal("endfile"),
perm_string::literal("$feof"),
fn_endfile_args, &type_BOOLEAN);
std_subprograms[fn_endfile->name()] = fn_endfile;
args, &type_BOOLEAN));
}
void delete_std_funcs()
{
for(std::map<perm_string,SubprogramHeader*>::iterator it = std_subprograms.begin();
it != std_subprograms.end(); ++it) {
delete it->second;
for(std::map<perm_string,SubHeaderList>::iterator cur = std_subprograms.begin();
cur != std_subprograms.end(); ++cur) {
for(SubHeaderList::const_iterator it = cur->second.begin();
it != cur->second.end(); ++it) {
delete *it;
}
}
}
SubprogramHeader*find_std_subprogram(perm_string name)
SubHeaderList 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;
map<perm_string,SubHeaderList>::const_iterator cur = std_subprograms.find(name);
if(cur != std_subprograms.end())
return cur->second;
return NULL;
return SubHeaderList();
}

View File

@ -1,7 +1,7 @@
#ifndef IVL_std_funcs_H
#define IVL_std_funcs_H
/*
* Copyright CERN 2015
* Copyright CERN 2016
* @author Maciej Suminski (maciej.suminski@cern.ch)
*
* This source code is free software; you can redistribute it
@ -29,6 +29,6 @@ void preload_std_funcs();
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);
SubHeaderList find_std_subprogram(perm_string name);
#endif /* IVL_std_funcs_H */

View File

@ -30,10 +30,11 @@ 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_TIME(VTypePrimitive::TIME);
const VTypePrimitive primitive_TIME(VTypePrimitive::TIME, true);
VTypeDef type_BOOLEAN(perm_string::literal("boolean"));
VTypeDef type_FILE_OPEN_KIND(perm_string::literal("file_open_kind"));
VTypeDef type_FILE_OPEN_STATUS(perm_string::literal("file_open_status"));
const VTypeArray primitive_CHARACTER(&primitive_BIT, 7, 0);
const VTypeArray primitive_BIT_VECTOR(&primitive_BIT, vector<VTypeArray::range_t> (1));
@ -64,6 +65,17 @@ void generate_global_types(ActiveScope*res)
std_types[type_FILE_OPEN_KIND.peek_name()] = &type_FILE_OPEN_KIND;
std_enums.push_back(enum_FILE_OPEN_KIND);
// file_open_status
list<perm_string> enum_FILE_OPEN_STATUS_vals;
enum_FILE_OPEN_STATUS_vals.push_back(perm_string::literal("open_ok"));
enum_FILE_OPEN_STATUS_vals.push_back(perm_string::literal("status_error"));
enum_FILE_OPEN_STATUS_vals.push_back(perm_string::literal("name_error"));
enum_FILE_OPEN_STATUS_vals.push_back(perm_string::literal("mode_error"));
VTypeEnum*enum_FILE_OPEN_STATUS = new VTypeEnum(&enum_FILE_OPEN_STATUS_vals);
type_FILE_OPEN_STATUS.set_definition(enum_FILE_OPEN_STATUS);
std_types[type_FILE_OPEN_STATUS.peek_name()] = &type_FILE_OPEN_STATUS;
std_enums.push_back(enum_FILE_OPEN_STATUS);
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);

View File

@ -39,6 +39,7 @@ extern const VTypePrimitive primitive_LINE;
extern VTypeDef type_BOOLEAN;
extern VTypeDef type_FILE_OPEN_KIND;
extern VTypeDef type_FILE_OPEN_STATUS;
extern const VTypeArray primitive_CHARACTER;
extern const VTypeArray primitive_BIT_VECTOR;

View File

@ -82,12 +82,13 @@ void SubprogramBody::write_to_stream(ostream&fd) const
} else {
fd << "--empty body" << endl;
}
fd << "end function;" << endl;
fd << "end function " << header_->name() << ";" << endl;
}
SubprogramHeader::SubprogramHeader(perm_string nam, list<InterfacePort*>*ports,
const VType*return_type)
: name_(nam), ports_(ports), return_type_(return_type), body_(NULL), parent_(NULL)
: name_(nam), ports_(ports), return_type_(return_type), body_(NULL), package_(NULL)
{
}
@ -171,12 +172,6 @@ const VType*SubprogramHeader::peek_param_type(int idx) const
return NULL;
}
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;
@ -200,6 +195,35 @@ void SubprogramHeader::set_body(SubprogramBody*bdy)
bdy->header_ = this;
}
int SubprogramHeader::elaborate_argument(Expression*expr, int idx,
Entity*ent, ScopeBase*scope)
{
const VType*type = expr->probe_type(ent, scope);
const InterfacePort*param = peek_param(idx);
if(!param) {
cerr << expr->get_fileline()
<< ": error: Too many arguments when calling "
<< name_ << "." << endl;
return 1;
}
// Enable reg_flag for variables that might be modified in subprograms
if(param->mode == PORT_OUT || param->mode == PORT_INOUT) {
if(const ExpName*e = dynamic_cast<const ExpName*>(expr)) {
if(Signal*sig = scope->find_signal(e->peek_name()))
sig->count_ref_sequ();
else if(Variable*var = scope->find_variable(e->peek_name()))
var->count_ref_sequ();
}
}
if(!type)
type = param->type;
return expr->elaborate_expr(ent, scope, type);
}
SubprogramHeader*SubprogramHeader::make_instance(std::vector<Expression*> arguments,
ScopeBase*scope) const {
assert(arguments.size() == ports_->size());
@ -233,7 +257,7 @@ SubprogramHeader*SubprogramHeader::make_instance(std::vector<Expression*> argume
}
body_inst->set_statements(body_->statements_);
instance->set_parent(scope);
instance->set_package(package_);
instance->set_body(body_inst);
instance->fix_return_type();
}
@ -334,13 +358,3 @@ void SubprogramHeader::write_to_stream(ostream&fd) const
return_type_->write_to_stream(fd);
}
}
SubprogramBuiltin::SubprogramBuiltin(perm_string vhdl_name, perm_string sv_name,
std::list<InterfacePort*>*ports, const VType*return_type)
: SubprogramHeader(vhdl_name, ports, return_type), sv_name_(sv_name)
{
}
SubprogramBuiltin::~SubprogramBuiltin()
{
}

View File

@ -31,8 +31,8 @@
class InterfacePort;
class SequentialStmt;
class Package;
class VType;
class SubprogramHeader;
class SubprogramBody : public LineInfo, public ScopeBase {
@ -54,6 +54,8 @@ class SubprogramBody : public LineInfo, public ScopeBase {
void write_to_stream(std::ostream&fd) const;
void dump(std::ostream&fd) const;
const SubprogramHeader*header() const { return header_; }
private:
std::list<SequentialStmt*>*statements_;
SubprogramHeader*header_;
@ -71,13 +73,14 @@ class SubprogramHeader : public LineInfo {
// matches this subprogram and that subprogram.
bool compare_specification(SubprogramHeader*that) const;
int param_count() const { return ports_ ? ports_->size() : 0; }
const InterfacePort*find_param(perm_string nam) const;
const InterfacePort*peek_param(int idx) const;
const VType*peek_param_type(int idx) const;
const VType*peek_return_type() const { return return_type_; }
void set_parent(const ScopeBase*par);
inline const ScopeBase*get_parent() const { return parent_; }
inline void set_package(const Package*pkg) { assert(!package_); package_ = pkg; }
inline const Package*get_package() const { return package_; }
// Checks if either return type or parameters are unbounded vectors.
bool unbounded() const;
@ -92,11 +95,18 @@ class SubprogramHeader : public LineInfo {
int elaborate() { return (body_ ? body_->elaborate() : 0); }
// Elaborates an argument basing on the types stored in the subprogram header.
int elaborate_argument(Expression*expr, int idx, Entity*ent, ScopeBase*scope);
// Emits the function name, including the package if required.
int emit_full_name(const std::vector<Expression*>&argv,
std::ostream&out, Entity*, ScopeBase*) const;
// 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*>&,
virtual int emit_name(const std::vector<Expression*>&argv,
std::ostream&out, Entity*, ScopeBase*) const;
// Emit arguments for a specific call. It allows to reorder or skip
@ -129,18 +139,29 @@ class SubprogramHeader : public LineInfo {
std::list<InterfacePort*>*ports_;
const VType*return_type_;
SubprogramBody*body_;
const ScopeBase*parent_;
const Package*package_;
};
// Class to define functions headers defined in the standard VHDL libraries.
class SubprogramBuiltin : public SubprogramHeader
class SubprogramStdHeader : public SubprogramHeader
{
public:
SubprogramStdHeader(perm_string name, std::list<InterfacePort*>*ports,
const VType*return_type) :
SubprogramHeader(name, ports, return_type) {}
virtual ~SubprogramStdHeader() {};
bool is_std() const { return true; }
};
// The simplest case, when only function name has to be changed.
class SubprogramBuiltin : public SubprogramStdHeader
{
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; }
std::list<InterfacePort*>*ports, const VType*return_type) :
SubprogramStdHeader(vhdl_name, ports, return_type), sv_name_(sv_name) {}
~SubprogramBuiltin() {}
int emit_name(const std::vector<Expression*>&, std::ostream&out, Entity*, ScopeBase*) const;
@ -149,4 +170,8 @@ class SubprogramBuiltin : public SubprogramHeader
perm_string sv_name_;
};
// Helper function to print out a human-readable function signature.
void emit_subprogram_sig(std::ostream&out, perm_string name,
const std::list<const VType*>&arg_types);
#endif /* IVL_subprogram_H */

View File

@ -21,6 +21,7 @@
# include "subprogram.h"
# include "sequential.h"
# include "vtype.h"
# include "package.h"
# include <iostream>
using namespace std;
@ -97,6 +98,22 @@ int SubprogramHeader::emit_package(ostream&fd) const
return errors;
}
int SubprogramHeader::emit_full_name(const std::vector<Expression*>&argv,
std::ostream&out, Entity*ent, ScopeBase*scope) const
{
// 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. It should not be emitted only if we call another
// function from the same package.
const SubprogramBody*subp = dynamic_cast<const SubprogramBody*>(scope);
if (package_ && (!subp || !subp->header() || subp->header()->get_package() != package_))
out << "\\" << package_->name() << " ::";
return emit_name(argv, out, ent, scope);
}
int SubprogramHeader::emit_name(const std::vector<Expression*>&,
std::ostream&out, Entity*, ScopeBase*) const
{
@ -124,3 +141,23 @@ int SubprogramBuiltin::emit_name(const std::vector<Expression*>&,
out << sv_name_;
return 0;
}
void emit_subprogram_sig(ostream&out, perm_string name,
const list<const VType*>&arg_types)
{
out << name << "(";
bool first = true;
for(list<const VType*>::const_iterator it = arg_types.begin();
it != arg_types.end(); ++it) {
if(first)
first = false;
else
out << ", ";
if(*it)
(*it)->write_to_stream(out);
else
out << "<unresolved type>";
}
out << ")";
}

View File

@ -22,6 +22,7 @@
# include "vsignal.h"
# include "expression.h"
# include "vtype.h"
# include "std_types.h"
# include <iostream>
using namespace std;
@ -35,11 +36,12 @@ SigVarBase::~SigVarBase()
{
}
void SigVarBase::elaborate_init_expr(Entity*ent, ScopeBase*scope)
void SigVarBase::elaborate(Entity*ent, ScopeBase*scope)
{
if(init_expr_) {
if(init_expr_)
init_expr_->elaborate_expr(ent, scope, peek_type());
}
type_->elaborate(ent, scope);
}
void SigVarBase::type_elaborate_(VType::decl_t&decl)
@ -53,14 +55,21 @@ int Signal::emit(ostream&out, Entity*ent, ScopeBase*scope)
VType::decl_t decl;
type_elaborate_(decl);
if (peek_refcnt_sequ_() > 0 || !peek_type()->can_be_packed())
const VType*type = peek_type();
if (peek_refcnt_sequ_() > 0
|| (!type->can_be_packed() && dynamic_cast<const VTypeArray*>(type)))
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);
/* Emit initialization value for wires as a weak assignment */
if(!decl.reg_flag && !type->type_match(&primitive_REAL))
out << ";" << endl << "/*init*/ assign (weak1, weak0) " << peek_name();
out << " = ";
init_expr->emit(out, ent, scope);
}
out << ";" << endl;
return errors;

View File

@ -42,8 +42,8 @@ class SigVarBase : public LineInfo {
void dump(ostream&out, int indent = 0) const;
// Elaborates initializer expressions if needed.
void elaborate_init_expr(Entity*ent, ScopeBase*scope);
// Elaborates type & initializer expressions.
void elaborate(Entity*ent, ScopeBase*scope);
perm_string peek_name() const { return name_; }

View File

@ -72,6 +72,10 @@ class VType {
// definitions. Most types accept the default definition of this.
virtual void write_type_to_stream(std::ostream&fd) const;
// Emits a type definition. This is used to distinguish types and
// subtypes.
virtual void write_typedef_to_stream(std::ostream&fd, perm_string name) const;
// This virtual method writes a human-readable version of the
// type to a given file for debug purposes. (Question: is this
// really necessary given the write_to_stream method?)
@ -105,8 +109,6 @@ class VType {
// to evaluate.
virtual int get_width(ScopeBase*) const { return -1; }
private:
friend struct decl_t;
// This virtual method is called to emit the declaration. This
// is used by the decl_t object to emit variable/wire/port declarations.
virtual int emit_decl(std::ostream&out, perm_string name, bool reg_flag) const;
@ -164,6 +166,7 @@ class VTypePrimitive : public VType {
VType*clone() const { return new VTypePrimitive(*this); }
bool type_match(const VType*that) const;
void write_to_stream(std::ostream&fd) const;
void show(std::ostream&) const;
int get_width(ScopeBase*scope) const;
@ -217,6 +220,7 @@ class VTypeArray : public VType {
VType*clone() const;
int elaborate(Entity*ent, ScopeBase*scope) const;
bool type_match(const VType*that) const;
void write_to_stream(std::ostream&fd) const;
void write_type_to_stream(std::ostream&fd) const;
void show(std::ostream&) const;
@ -274,11 +278,12 @@ class VTypeRange : public VType {
bool write_std_types(std::ostream&fd) const;
int emit_def(std::ostream&out, perm_string name) const;
bool type_match(const VType*that) const;
// Get the type that is limited by the range.
inline const VType*base_type() const { return base_; }
private:
protected:
const VType*base_;
};
@ -291,7 +296,9 @@ class VTypeRangeConst : public VTypeRange {
return new VTypeRangeConst(base_type()->clone(), start_, end_);
}
public: // Virtual methods
int64_t start() const { return start_; }
int64_t end() const { return end_; }
void write_to_stream(std::ostream&fd) const;
private:
@ -305,6 +312,7 @@ class VTypeRangeExpr : public VTypeRange {
~VTypeRangeExpr();
VType*clone() const;
int elaborate(Entity*end, ScopeBase*scope) const;
public: // Virtual methods
void write_to_stream(std::ostream&fd) const;
@ -330,6 +338,7 @@ class VTypeEnum : public VType {
int get_width(ScopeBase*) const { return 32; }
int emit_def(std::ostream&out, perm_string name) const;
int emit_decl(std::ostream&out, perm_string name, bool reg_flag) const;
// Checks if the name is stored in the enum.
bool has_name(perm_string name) const;
@ -383,7 +392,7 @@ class VTypeDef : public VType {
public:
explicit VTypeDef(perm_string name);
explicit VTypeDef(perm_string name, const VType*is);
~VTypeDef();
virtual ~VTypeDef();
VType*clone() const { return new VTypeDef(*this); }
@ -399,22 +408,28 @@ class VTypeDef : public VType {
// type, and this method gets it for us.
inline const VType* peek_definition(void) const { return type_; }
void write_to_stream(std::ostream&fd) const;
virtual void write_to_stream(std::ostream&fd) const;
void write_type_to_stream(std::ostream&fd) const;
int get_width(ScopeBase*scope) const { return type_->get_width(scope); }
int emit_typedef(std::ostream&out, typedef_context_t&ctx) const;
int emit_def(std::ostream&out, perm_string name) const;
int emit_decl(std::ostream&out, perm_string name, bool reg_flag) const;
bool can_be_packed() const { return type_->can_be_packed(); }
bool is_unbounded() const { return type_->is_unbounded(); }
private:
int emit_decl(std::ostream&out, perm_string name, bool reg_flag) const;
private:
protected:
perm_string name_;
const VType*type_;
};
class VSubTypeDef : public VTypeDef {
public:
explicit VSubTypeDef(perm_string name) : VTypeDef(name) {}
explicit VSubTypeDef(perm_string name, const VType*is) : VTypeDef(name, is) {}
void write_typedef_to_stream(std::ostream&fd, perm_string name) const;
};
#endif /* IVL_vtype_H */

View File

@ -29,7 +29,8 @@ int VType::elaborate(Entity*, ScopeBase*) const
int VTypeArray::elaborate(Entity*ent, ScopeBase*scope) const
{
int errors = 0;
etype_->elaborate(ent, scope);
errors += etype_->elaborate(ent, scope);
for (vector<range_t>::const_iterator cur = ranges_.begin()
; cur != ranges_.end() ; ++ cur) {
@ -43,3 +44,14 @@ int VTypeArray::elaborate(Entity*ent, ScopeBase*scope) const
return errors;
}
int VTypeRangeExpr::elaborate(Entity*ent, ScopeBase*scope) const
{
int errors = 0;
errors += base_->elaborate(ent, scope);
errors += start_->elaborate_expr(ent, scope, 0);
errors += end_->elaborate_expr(ent, scope, 0);
return errors;
}

View File

@ -98,9 +98,21 @@ int VTypeArray::emit_with_dims_(std::ostream&out, bool packed, perm_string name)
list<const VTypeArray*> dims;
const VTypeArray*cur = this;
while (const VTypeArray*sub = dynamic_cast<const VTypeArray*> (cur->element_type())) {
dims.push_back(cur);
cur = sub;
bool added_dim = true;
while(added_dim) {
added_dim = false;
const VType*el_type = cur->element_type();
while(const VTypeDef*tdef = dynamic_cast<const VTypeDef*>(el_type)) {
el_type = tdef->peek_definition();
}
if(const VTypeArray*sub = dynamic_cast<const VTypeArray*>(el_type)) {
dims.push_back(cur);
cur = sub;
added_dim = true;
}
}
dims.push_back(cur);
@ -122,9 +134,9 @@ int VTypeArray::emit_with_dims_(std::ostream&out, bool packed, perm_string name)
}
out << "[";
if (!cur->dimension(i).is_box()) { // if not unbounded {
if (!cur->dimension(i).is_box()) { // if not unbounded
errors += cur->dimension(i).msb()->emit(out, 0, 0);
out << ":";
out << ":";
errors += cur->dimension(i).lsb()->emit(out, 0, 0);
}
out << "]";
@ -141,7 +153,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 integer {";
out << "enum int {";
assert(names_.size() >= 1);
out << "\\" << names_[0] << " ";
for (size_t idx = 1 ; idx < names_.size() ; idx += 1)
@ -153,6 +165,17 @@ int VTypeEnum::emit_def(ostream&out, perm_string name) const
return errors;
}
int VTypeEnum::emit_decl(std::ostream&out, perm_string name, bool reg_flag) const
{
if (!reg_flag)
out << "wire ";
out << "int";
emit_name(out, name);
return 0;
}
int VTypePrimitive::emit_primitive_type(ostream&out) const
{
int errors = 0;
@ -223,28 +246,15 @@ int VTypeRecord::emit_def(ostream&out, perm_string name) const
*/
int VTypeDef::emit_def(ostream&out, perm_string name) const
{
int errors = 0;
emit_name(out, name_);
emit_name(out, name);
return errors;
return 0;
}
int VTypeDef::emit_decl(ostream&out, perm_string name, bool reg_flag) const
{
int errors = 0;
if (!dynamic_cast<const VTypeEnum*>(type_))
out << (reg_flag ? "reg " : "wire ");
if(dynamic_cast<const VTypeArray*>(type_)) {
errors += type_->emit_def(out, name);
} else {
assert(name_ != empty_perm_string);
cout << "\\" << name_;
emit_name(out, name);
}
return errors;
return type_->emit_decl(out, name, reg_flag);
}
int VTypeDef::emit_typedef(ostream&out, typedef_context_t&ctx) const

View File

@ -38,5 +38,61 @@ bool VTypeDef::type_match(const VType*that) const
if(VType::type_match(that))
return true;
return VType::type_match(type_);
return type_->type_match(that);
}
bool VTypePrimitive::type_match(const VType*that) const
{
if(VType::type_match(that))
return true;
if(const VTypePrimitive*prim = dynamic_cast<const VTypePrimitive*>(that)) {
// TODO it is not always true, but works for many cases
type_t that_type = prim->type();
return ((type_ == NATURAL || type_ == INTEGER) &&
(that_type == NATURAL || that_type == INTEGER));
}
if(const VTypeRangeConst*range = dynamic_cast<const VTypeRangeConst*>(that)) {
if (type_ == INTEGER)
return true;
if (type_ == NATURAL && range->start() >= 0 && range->end() >= 0)
return true;
}
return false;
}
bool VTypeArray::type_match(const VType*that) const
{
if(VType::type_match(that))
return true;
// Check if both arrays are of the same size
if(const VTypeArray*arr = dynamic_cast<const VTypeArray*>(that)) {
if(!element_type()->type_match(arr->element_type()))
return false;
int this_width = get_width(NULL);
int that_width = arr->get_width(NULL);
// Either one of the sizes is undefined, or both are the same size
if(this_width > 0 && that_width > 0 && this_width != that_width)
return false;
return true;
}
return false;
}
bool VTypeRange::type_match(const VType*that) const
{
if(VType::type_match(that))
return true;
if(base_->type_match(that))
return true;
return false;
}

View File

@ -36,6 +36,16 @@ void VType::write_type_to_stream(ostream&fd) const
write_to_stream(fd);
}
void VType::write_typedef_to_stream(ostream&fd, perm_string name) const
{
if(is_global_type(name))
return;
fd << "type " << name << " is ";
write_type_to_stream(fd);
fd << ";" << endl;
}
void VTypeArray::write_to_stream(ostream&fd) const
{
if(write_special_case(fd))
@ -238,3 +248,12 @@ void VTypeEnum::write_to_stream(std::ostream&fd) const
fd << ")";
}
void VSubTypeDef::write_typedef_to_stream(ostream&fd, perm_string name) const
{
if(is_global_type(name))
return;
fd << "subtype " << name << " is ";
write_type_to_stream(fd);
fd << ";" << endl;
}

View File

@ -75,7 +75,7 @@ V = va_math.o
V2009 = v2009_table.o v2009_array.o v2009_enum.o v2009_string.o
VHDL_SYS = vhdl_table.o
VHDL_SYS = vhdl_table.o sys_priv.o
VHDL_TEXTIO = vhdl_textio.o sys_priv.o

View File

@ -1,3 +1,6 @@
$ivlh_attribute_event vpiSysFuncSized 1 unsigned
$ivlh_rising_edge vpiSysFuncSized 1 unsigned
$ivlh_falling_edge vpiSysFuncSized 1 unsigned
$ivlh_shift_left vpiSysFuncSized 32 unsigned
$ivlh_shift_right vpiSysFuncSized 32 unsigned

View File

@ -21,6 +21,7 @@
# include "vpi_user.h"
# include <assert.h>
# include "ivl_alloc.h"
# include "sys_priv.h"
/*
* The $ivlh_attribute_event implements the VHDL <varname>'event
@ -40,11 +41,24 @@ struct monitor_data {
static struct monitor_data **mdata = 0;
static unsigned mdata_count = 0;
typedef enum { EVENT = 0, RISING_EDGE = 1, FALLING_EDGE = 2 } event_type_t;
static const char* func_names[] = {
"$ivlh_attribute_event",
"$ivlh_rising_edge",
"$ivlh_falling_edge"
typedef enum {
EVENT = 0,
RISING_EDGE = 1,
FALLING_EDGE = 2
} event_type_t;
static const char* attr_func_names[] = {
"$ivlh_attribute_event",
"$ivlh_rising_edge",
"$ivlh_falling_edge"
};
typedef enum {
SHIFT_LEFT = 0,
SHIFT_RIGHT = 1,
} shift_type_t;
static const char* shift_func_names[] = {
"$ivlh_shift_left",
"$ivlh_shift_right",
};
/* To keep valgrind happy free the allocated memory. */
@ -93,7 +107,7 @@ static PLI_INT32 ivlh_attribute_event_compiletf(ICARUS_VPI_CONST PLI_BYTE8*data)
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys),
(int)vpi_get(vpiLineNo, sys));
vpi_printf("(compiler error) %s requires a single argument.\n",
func_names[type]);
attr_func_names[type]);
vpi_control(vpiFinish, 1);
return 0;
}
@ -127,7 +141,7 @@ static PLI_INT32 ivlh_attribute_event_compiletf(ICARUS_VPI_CONST PLI_BYTE8*data)
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys),
(int)vpi_get(vpiLineNo, sys));
vpi_printf("(compiler error) %s only takes a single argument.\n",
func_names[type]);
attr_func_names[type]);
vpi_free_object(argv);
vpi_control(vpiFinish, 1);
}
@ -180,39 +194,83 @@ static PLI_INT32 ivlh_attribute_event_sizetf(ICARUS_VPI_CONST PLI_BYTE8*type)
return 1;
}
static PLI_INT32 ivlh_shift_calltf(ICARUS_VPI_CONST PLI_BYTE8*data)
{
shift_type_t shift_type = (shift_type_t) data;
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle argh = vpi_scan(argv);
vpiHandle counth = vpi_scan(argv);
s_vpi_value val;
PLI_INT32 count;
vpi_free_object(argv);
val.format = vpiIntVal;
vpi_get_value(counth, &val);
count = val.value.integer;
val.format = vpiIntVal;
vpi_get_value(argh, &val);
if(shift_type == SHIFT_LEFT)
val.value.integer <<= count;
else if(shift_type == SHIFT_RIGHT)
val.value.integer >>= count;
else
assert(0);
vpi_put_value(callh, &val, 0, vpiNoDelay);
return 0;
}
static PLI_INT32 ivlh_shift_sizetf(ICARUS_VPI_CONST PLI_BYTE8*type)
{
(void) type; /* Parameter is not used. */
return 32;
}
static void vhdl_register(void)
{
s_vpi_systf_data tf_data;
s_cb_data cb;
vpiHandle res;
/* Event attribute functions */
tf_data.type = vpiSysFunc;
tf_data.sysfunctype = vpiSizedFunc;
tf_data.calltf = ivlh_attribute_event_calltf;
tf_data.compiletf = ivlh_attribute_event_compiletf;
tf_data.sizetf = ivlh_attribute_event_sizetf;
tf_data.tfname = func_names[EVENT];
tf_data.tfname = attr_func_names[EVENT];
tf_data.user_data = (PLI_BYTE8*) EVENT;
res = vpi_register_systf(&tf_data);
vpip_make_systf_system_defined(res);
tf_data.type = vpiSysFunc;
tf_data.sysfunctype = vpiSizedFunc;
tf_data.calltf = ivlh_attribute_event_calltf;
tf_data.compiletf = ivlh_attribute_event_compiletf;
tf_data.sizetf = ivlh_attribute_event_sizetf;
tf_data.tfname = func_names[RISING_EDGE];
tf_data.tfname = attr_func_names[RISING_EDGE];
tf_data.user_data = (PLI_BYTE8*) RISING_EDGE;
res = vpi_register_systf(&tf_data);
vpip_make_systf_system_defined(res);
tf_data.tfname = attr_func_names[FALLING_EDGE];
tf_data.user_data = (PLI_BYTE8*) FALLING_EDGE;
res = vpi_register_systf(&tf_data);
vpip_make_systf_system_defined(res);
/* Shift functions */
tf_data.type = vpiSysFunc;
tf_data.sysfunctype = vpiSizedFunc;
tf_data.calltf = ivlh_attribute_event_calltf;
tf_data.compiletf = ivlh_attribute_event_compiletf;
tf_data.sizetf = ivlh_attribute_event_sizetf;
tf_data.tfname = func_names[FALLING_EDGE];
tf_data.user_data = (PLI_BYTE8*) FALLING_EDGE;
tf_data.calltf = ivlh_shift_calltf;
tf_data.compiletf = sys_two_numeric_args_compiletf;
tf_data.sizetf = ivlh_shift_sizetf;
tf_data.tfname = shift_func_names[SHIFT_LEFT];
tf_data.user_data = (PLI_BYTE8*) SHIFT_LEFT;
res = vpi_register_systf(&tf_data);
vpip_make_systf_system_defined(res);
tf_data.tfname = shift_func_names[SHIFT_RIGHT];
tf_data.user_data = (PLI_BYTE8*) SHIFT_RIGHT;
res = vpi_register_systf(&tf_data);
vpip_make_systf_system_defined(res);

View File

@ -48,6 +48,7 @@
# include <assert.h>
# include <string.h>
# include <ctype.h>
# include <errno.h>
# include "ivl_alloc.h"
/* additional parameter values to distinguish between integer, boolean and
@ -55,10 +56,14 @@
enum format_t { FORMAT_STD, FORMAT_BOOL, FORMAT_TIME, FORMAT_HEX, FORMAT_STRING };
enum file_mode_t { FILE_MODE_READ, FILE_MODE_WRITE, FILE_MODE_APPEND, FILE_MODE_LAST };
enum file_open_status_t { FS_OPEN_OK, FS_STATUS_ERROR, FS_NAME_ERROR, FS_MODE_ERROR };
/* bits per vector, in a single s_vpi_vecval struct */
static const size_t BPW = 8 * sizeof(PLI_INT32);
/* string buffer size */
static const size_t STRING_BUF_SIZE = 1024;
static int is_integer_var(vpiHandle obj)
{
PLI_INT32 type = vpi_get(vpiType, obj);
@ -67,6 +72,11 @@ static int is_integer_var(vpiHandle obj)
type == vpiIntVar || type == vpiLongIntVar);
}
static int is_const(vpiHandle obj)
{
return vpi_get(vpiType, obj) == vpiConstant;
}
static void show_error_line(vpiHandle callh) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
@ -82,7 +92,7 @@ static int set_vec_val(s_vpi_vecval* vector, char value, int idx) {
s_vpi_vecval*v = &vector[idx / BPW];
PLI_INT32 bit = idx % BPW;
switch(toupper(value)) {
switch(value) {
case '0':
v->bval &= ~(1 << bit);
v->aval &= ~(1 << bit);
@ -93,11 +103,13 @@ static int set_vec_val(s_vpi_vecval* vector, char value, int idx) {
v->aval |= (1 << bit);
break;
case 'z':
case 'Z':
v->bval |= (1 << bit);
v->aval &= ~(1 << bit);
break;
case 'x':
case 'X':
v->bval |= (1 << bit);
v->aval |= (1 << bit);
@ -217,11 +229,18 @@ static int read_time(const char *string, s_vpi_value *val, PLI_INT32 scope_unit)
return processed_chars;
}
static int read_string(const char *string, s_vpi_value *val) {
char buf[1024];
static int read_string(const char *string, s_vpi_value *val, int count) {
char buf[STRING_BUF_SIZE];
int processed_chars;
char format_str[32];
if(sscanf(string, "%1024s%n", buf, &processed_chars) != 1)
/* No string length limit imposed */
if(count == 0)
count = STRING_BUF_SIZE;
snprintf(format_str, 32, "%%%ds%%n", count);
if(sscanf(string, format_str, buf, &processed_chars) != 1)
return 0;
val->format = vpiStringVal;
@ -281,40 +300,44 @@ static int write_time(char *string, const s_vpi_value* val,
static PLI_INT32 ivlh_file_open_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv;
vpiHandle argv, arg;
assert(callh != 0);
int ok = 1;
argv = vpi_iterate(vpiArgument, callh);
/* Check that there is a file name argument and that it is a string. */
if (argv == 0) {
show_error_line(callh);
vpi_printf("%s requires a string file name argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
if (argv == 0)
ok = 0;
if(!is_integer_var(vpi_scan(argv))) {
show_error_line(callh);
vpi_printf("%s's first argument has to be an integer variable (file handle).\n", name);
vpi_control(vpiFinish, 1);
}
arg = vpi_scan(argv);
if (!arg || !is_integer_var(arg))
ok = 0;
if(!is_string_obj(vpi_scan(argv))) {
show_error_line(callh);
vpi_printf("%s's second argument argument must be a string (file name).\n", name);
vpi_control(vpiFinish, 1);
}
arg = vpi_scan(argv);
if (arg && is_integer_var(arg))
arg = vpi_scan(argv);
/* When provided, the type argument must be a string. */
if(!vpi_scan(argv)) {
// no vpi_scan() here, if we had both 'status' and 'file' arguments,
// then the next arg is read in the above if, otherwise we are going
// to check the second argument once again
if (!arg || !is_string_obj(arg))
ok = 0;
arg = vpi_scan(argv);
if (arg && !is_const(arg))
ok = 0;
if (!ok) {
show_error_line(callh);
vpi_printf("%s's third argument must be an integer (open mode).\n", name);
vpi_printf("%s() function is available in following variants:\n", name);
vpi_printf("* (file f: text; filename: in string, file_open_kind: in mode)\n");
vpi_printf("* (status: out file_open_status, file f: text; filename: in string, file_open_kind: in mode)\n");
vpi_control(vpiFinish, 1);
}
/* Make sure there are no extra arguments. */
check_for_extra_args(argv, callh, name, "three arguments", 1);
check_for_extra_args(argv, callh, name, "four arguments", 1);
return 0;
}
@ -330,15 +353,25 @@ static PLI_INT32 ivlh_file_open_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
int mode;
char *fname;
vpiHandle fstatush = vpi_scan(argv);
vpiHandle fhandleh = vpi_scan(argv);
vpiHandle fnameh = vpi_scan(argv);
vpiHandle modeh = vpi_scan(argv);
if(!modeh) {
/* There are only three arguments, so rearrange handles */
modeh = fnameh;
fnameh = fhandleh;
fhandleh = fstatush;
fstatush = 0;
} else {
vpi_free_object(argv);
}
/* Get the mode handle */
val.format = vpiIntVal;
vpi_get_value(modeh, &val);
mode = val.value.integer;
vpi_free_object(argv);
if(mode < 0 || mode >= FILE_MODE_LAST) {
show_error_line(callh);
@ -355,21 +388,51 @@ static PLI_INT32 ivlh_file_open_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
}
/* Open file and save the handle */
PLI_INT32 result = -1;
switch(mode) {
case FILE_MODE_READ:
val.value.integer = vpi_fopen(fname, "r");
result = vpi_fopen(fname, "r");
break;
case FILE_MODE_WRITE:
val.value.integer = vpi_fopen(fname, "w");
result = vpi_fopen(fname, "w");
break;
case FILE_MODE_APPEND:
val.value.integer = vpi_fopen(fname, "a");
result = vpi_fopen(fname, "a");
break;
}
if(fstatush) {
val.format = vpiIntVal;
if(!result) {
switch(errno) {
case ENOENT:
case ENAMETOOLONG:
val.value.integer = FS_NAME_ERROR;
break;
case EINVAL:
case EACCES:
case EEXIST:
case EISDIR:
val.value.integer = FS_MODE_ERROR;
break;
default:
val.value.integer = FS_STATUS_ERROR;
break;
}
} else {
val.value.integer = FS_OPEN_OK;
}
vpi_put_value(fstatush, &val, 0, vpiNoDelay);
}
val.format = vpiIntVal;
val.value.integer = result;
vpi_put_value(fhandleh, &val, 0, vpiNoDelay);
free(fname);
@ -422,8 +485,7 @@ static PLI_INT32 ivlh_readline_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
PLI_UINT32 fd;
FILE *fp;
char *text;
const int BUF_SIZE = 1024;
char buf[BUF_SIZE];
char buf[STRING_BUF_SIZE];
/* Get the file descriptor. */
arg = vpi_scan(argv);
@ -445,7 +507,7 @@ static PLI_INT32 ivlh_readline_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
}
/* Read in the bytes. Return 0 if there was an error. */
if(fgets(buf, BUF_SIZE, fp) == 0) {
if(fgets(buf, STRING_BUF_SIZE, fp) == 0) {
show_error_line(callh);
vpi_printf("%s reading past the end of file.\n", name);
@ -458,7 +520,7 @@ static PLI_INT32 ivlh_readline_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
show_error_line(callh);
vpi_printf("%s read 0 bytes.\n", name);
return 0;
} else if(len == BUF_SIZE - 1) {
} else if(len == STRING_BUF_SIZE - 1) {
show_warning_line(callh);
vpi_printf("%s has reached the buffer limit, part of the "
"processed string might have been skipped.\n", name);
@ -471,6 +533,11 @@ static PLI_INT32 ivlh_readline_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
vpi_put_value(stringh, &val, 0, vpiNoDelay);
free(text);
/* Set end-of-file flag if we have just reached the end of the file.
* Otherwise the flag would be set only after the next read operation. */
int c = fgetc(fp);
ungetc(c, fp);
return 0;
}
@ -569,19 +636,15 @@ static PLI_INT32 ivlh_read_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle stringh, varh, formath;
s_vpi_value val;
PLI_INT32 type, format;
PLI_INT32 type, format, dest_size;
char *string = 0;
int processed_chars = 0, fail = 0;
unsigned int processed_chars = 0, fail = 0;
/* Get the string */
stringh = vpi_scan(argv);
val.format = vpiStringVal;
vpi_get_value(stringh, &val);
/* Get the destination variable */
varh = vpi_scan(argv);
type = vpi_get(vpiType, varh);
if(strlen(val.value.str) == 0) {
show_error_line(callh);
vpi_printf("%s cannot read from an empty string.\n", name);
@ -590,6 +653,11 @@ static PLI_INT32 ivlh_read_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
string = strdup(val.value.str);
/* Get the destination variable */
varh = vpi_scan(argv);
type = vpi_get(vpiType, varh);
dest_size = vpi_get(vpiSize, varh);
/* Get the format (see enum format_t) */
formath = vpi_scan(argv);
val.format = vpiIntVal;
@ -623,7 +691,7 @@ static PLI_INT32 ivlh_read_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
break;
case vpiStringVar:
processed_chars = read_string(string, &val);
processed_chars = read_string(string, &val, dest_size / 8);
break;
default:
@ -663,7 +731,7 @@ static PLI_INT32 ivlh_read_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
break;
case FORMAT_STRING:
processed_chars = read_string(string, &val);
processed_chars = read_string(string, &val, dest_size / 8);
break;
}
@ -671,7 +739,7 @@ static PLI_INT32 ivlh_read_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
show_error_line(callh);
vpi_printf("%s could not read a valid value.\n", name);
fail = 1;
} else if(val.format == vpiStringVar && processed_chars == 1024) {
} else if(val.format == vpiStringVar && processed_chars == STRING_BUF_SIZE) {
show_warning_line(callh);
vpi_printf("%s has reached the buffer limit, part of the "
"processed string might have been skipped.\n", name);
@ -759,9 +827,8 @@ static PLI_INT32 ivlh_write_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
s_vpi_value val;
PLI_INT32 type, format;
char *string = 0;
int fail = 0, res = 0;
const int BUF_SIZE = 1024;
char buf[BUF_SIZE];
unsigned int fail = 0, res = 0;
char buf[STRING_BUF_SIZE];
/* Get the string */
stringh = vpi_scan(argv);
@ -794,11 +861,14 @@ static PLI_INT32 ivlh_write_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
break;
case vpiDecConst:
case vpiBinaryConst:
case vpiOctConst:
case vpiHexConst:
type = vpiIntVar;
break;
case vpiBinaryConst:
type = vpiBitVar;
break;
}
}
@ -813,7 +883,7 @@ static PLI_INT32 ivlh_write_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
case vpiIntegerVar:
val.format = vpiIntVal;
vpi_get_value(varh, &val);
res = snprintf(buf, BUF_SIZE, "%s%d", string, val.value.integer);
res = snprintf(buf, STRING_BUF_SIZE, "%s%d", string, val.value.integer);
break;
case vpiBitVar: /* bit, bit vector */
@ -825,19 +895,19 @@ static PLI_INT32 ivlh_write_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
for(size_t i = 0; i< strlen(val.value.str); ++i)
val.value.str[i] = toupper(val.value.str[i]);
res = snprintf(buf, BUF_SIZE, "%s%s", string, val.value.str);
res = snprintf(buf, STRING_BUF_SIZE, "%s%s", string, val.value.str);
break;
case vpiRealVar:
val.format = vpiRealVal;
vpi_get_value(varh, &val);
res = snprintf(buf, BUF_SIZE, "%s%lf", string, val.value.real);
res = snprintf(buf, STRING_BUF_SIZE, "%s%lf", string, val.value.real);
break;
case vpiStringVar:
val.format = vpiStringVal;
vpi_get_value(varh, &val);
res = snprintf(buf, BUF_SIZE, "%s%s", string, val.value.str);
res = snprintf(buf, STRING_BUF_SIZE, "%s%s", string, val.value.str);
break;
default:
@ -851,7 +921,7 @@ static PLI_INT32 ivlh_write_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
case FORMAT_BOOL:
val.format = vpiIntVal;
vpi_get_value(varh, &val);
res = snprintf(buf, BUF_SIZE, "%s%s", string,
res = snprintf(buf, STRING_BUF_SIZE, "%s%s", string,
val.value.integer ? "TRUE" : "FALSE");
break;
@ -867,29 +937,29 @@ static PLI_INT32 ivlh_write_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
break;
}
res = snprintf(buf, BUF_SIZE, "%s%s", string, tmp);
res = snprintf(buf, STRING_BUF_SIZE, "%s%s", string, tmp);
}
break;
case FORMAT_HEX:
val.format = vpiIntVal;
vpi_get_value(varh, &val);
res = snprintf(buf, BUF_SIZE, "%s%X", string, val.value.integer);
res = snprintf(buf, STRING_BUF_SIZE, "%s%X", string, val.value.integer);
break;
case FORMAT_STRING:
val.format = vpiStringVal;
vpi_get_value(varh, &val);
res = snprintf(buf, BUF_SIZE, "%s%s", string, val.value.str);
res = snprintf(buf, STRING_BUF_SIZE, "%s%s", string, val.value.str);
break;
}
if(res > BUF_SIZE)
if(res > STRING_BUF_SIZE)
fail = 1;
if(!fail) {
/* Strip the read token from the string */
char* tmp = strndup(buf, BUF_SIZE);
char* tmp = strndup(buf, STRING_BUF_SIZE);
val.format = vpiStringVal;
val.value.str = tmp;
vpi_put_value(stringh, &val, 0, vpiNoDelay);

View File

@ -208,6 +208,15 @@ void vvp_fun_part_pv::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
port.ptr()->send_vec4_pv(bit, base_, wid_, vwid_, context);
}
void vvp_fun_part_pv::recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx)
{
assert(port.port() == 0);
port.ptr()->send_vec4_pv(bit, base, wid, vwid, ctx);
}
void vvp_fun_part_pv::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit)
{
assert(port.port() == 0);

View File

@ -109,6 +109,10 @@ class vvp_fun_part_pv : public vvp_net_fun_t {
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t context);
void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
unsigned, unsigned, unsigned,
vvp_context_t);
void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit);
private: