commit
6a8303bdaf
87
elab_net.cc
87
elab_net.cc
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
44
netmisc.cc
44
netmisc.cc
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,3 +21,5 @@
|
|||
StringHeapLex lex_strings;
|
||||
|
||||
StringHeapLex filename_strings;
|
||||
|
||||
StringHeapLex gen_strings;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
239
vhdlpp/parse.y
239
vhdlpp/parse.y
|
|
@ -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"), ¶ms);
|
||||
active_scope->add_initializer(fopen_call);
|
||||
ProcedureCall*fopen_call = new ProcedureCall(
|
||||
perm_string::literal("file_open"), ¶ms);
|
||||
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"), ¶ms);
|
||||
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"), ¶ms);
|
||||
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; }
|
||||
;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
238
vhdlpp/scope.cc
238
vhdlpp/scope.cc
|
|
@ -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())
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 << ")";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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_; }
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Reference in New Issue