diff --git a/elab_net.cc b/elab_net.cc index 09a38f454..55bdbce9c 100644 --- a/elab_net.cc +++ b/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; } diff --git a/netmisc.cc b/netmisc.cc index 2ced04acb..5a36e124d 100644 --- a/netmisc.cc +++ b/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&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; } diff --git a/vhdlpp/architec.cc b/vhdlpp/architec.cc index 2f1cea235..488ee9cd5 100644 --- a/vhdlpp/architec.cc +++ b/vhdlpp/architec.cc @@ -29,7 +29,7 @@ using namespace std; Architecture::Architecture(perm_string name, const ActiveScope&ref, list&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&options) +: lval_(target) +{ + options_.splice(options_.end(), options); +} + +CondSignalAssignment::~CondSignalAssignment() +{ + delete lval_; + for(list::iterator it = options_.begin(); + it != options_.end(); ++it) { + delete *it; + } +} + ComponentInstantiation::ComponentInstantiation(perm_string i, perm_string c, list*parms, list*ports) @@ -245,9 +268,10 @@ StatementList::~StatementList() } ProcessStatement::ProcessStatement(perm_string iname, + const ActiveScope&ref, std::list*sensitivity_list, std::list*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); diff --git a/vhdlpp/architec.h b/vhdlpp/architec.h index d33a33e57..3d9ef1f05 100644 --- a/vhdlpp/architec.h +++ b/vhdlpp/architec.h @@ -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 rval_; }; +class CondSignalAssignment : public Architecture::Statement { + + public: + CondSignalAssignment(ExpName*target, std::list&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 options_; + + // List of signals that should be emitted in the related process + // sensitivity list. It is filled during the elaboration step. + std::listsens_list_; +}; + class ComponentInstantiation : public Architecture::Statement { public: @@ -220,8 +252,16 @@ class StatementList : public Architecture::Statement { StatementList(std::list*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(arc)); + } + + int emit(ostream&out, Entity*ent, Architecture*arc) { + return emit(out, ent, static_cast(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& stmt_list() { return statements_; } @@ -237,7 +277,7 @@ class InitialStatement : public StatementList { InitialStatement(std::list*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*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*sensitivity_list, std::list*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 sensitivity_list_; }; diff --git a/vhdlpp/architec_debug.cc b/vhdlpp/architec_debug.cc index 630da357c..1a42aea28 100644 --- a/vhdlpp/architec_debug.cc +++ b/vhdlpp/architec_debug.cc @@ -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) << "" << "<= ..." << endl; + + for(list::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; diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index cfedeb467..5ec87becc 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -45,25 +45,30 @@ int Architecture::elaborate(Entity*entity) // Elaborate initializer expressions for signals & variables for (map::iterator cur = old_signals_.begin() ; cur != old_signals_.end() ; ++cur) { - cur->second->elaborate_init_expr(entity, this); + cur->second->elaborate(entity, this); } for (map::iterator cur = new_signals_.begin() ; cur != new_signals_.end() ; ++cur) { - cur->second->elaborate_init_expr(entity, this); + cur->second->elaborate(entity, this); } for (map::iterator cur = old_variables_.begin() ; cur != old_variables_.end() ; ++cur) { - cur->second->elaborate_init_expr(entity, this); + cur->second->elaborate(entity, this); } for (map::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::const_iterator cur = cur_subprograms_.begin() + for (map::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 ) 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 (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 - // 'event AND ='1'. - // So if ce_raw is not a logical AND, I give up. - const ExpLogical*ce = dynamic_cast (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(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(op1_raw); - if (op1 == 0) - return -1; - if (op1->peek_attribute() != "event") - return -1; - - const ExpRelation*op2 = dynamic_cast(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(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(op2b_raw); - if (op2b->value() != '1' && op2b->value() != '0') - return -1; - - // We've matched this pattern: - // process () if ('event and = ) then ... - // And we can convert it to: - // always @(edge ) ... - - // 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::iterator it = statements_.begin(); it != statements_.end(); ++it) { - errors += (*it)->elaborate(ent, arc); + errors += (*it)->elaborate(ent, scope); } return errors; } -/* - * Change the "process () " into "always @() ..." - */ -int ProcessStatement::extract_anyedge_(Entity*, Architecture*) -{ - vector 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::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& name_list) + : name_list_(name_list) {} + void operator() (Expression*s) { + if(const ExpName*name = dynamic_cast(s)) + name_list_.push_back(name); + } + + private: + list& 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::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; +} diff --git a/vhdlpp/architec_emit.cc b/vhdlpp/architec_emit.cc index e041d99cd..e5a3a1c61 100644 --- a/vhdlpp/architec_emit.cc +++ b/vhdlpp/architec_emit.cc @@ -23,42 +23,33 @@ # include "sequential.h" # include "subprogram.h" # include "vsignal.h" +# include "std_types.h" # include # include # include -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::iterator cur = old_signals_.begin() - ; cur != old_signals_.end() ; ++cur) { + for (map::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::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::iterator cur = old_variables_.begin() - ; cur != old_variables_.end() ; ++cur) { + for (map::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::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::iterator cur = use_types_.begin() - //; cur != use_types_.end() ; ++cur) { + for (map::iterator cur = use_types_.begin() + ; cur != use_types_.end() ; ++cur) { + if(is_global_type(cur->first)) + continue; - //if(const VTypeDef*def = dynamic_cast(cur->second)) - //errors += def->emit_typedef(out, typedef_ctx); - //} + if(const VTypeDef*def = dynamic_cast(cur->second)) + errors += def->emit_typedef(out, typedef_ctx); + } for (map::iterator cur = cur_types_.begin() ; cur != cur_types_.end() ; ++cur) { - if(const VTypeDef*def = dynamic_cast(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::const_iterator cur = cur_subprograms_.begin() + for (map::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::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(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_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::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::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(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; - } diff --git a/vhdlpp/compiler.cc b/vhdlpp/compiler.cc index 66193a370..9a1a6279e 100644 --- a/vhdlpp/compiler.cc +++ b/vhdlpp/compiler.cc @@ -21,3 +21,5 @@ StringHeapLex lex_strings; StringHeapLex filename_strings; + +StringHeapLex gen_strings; diff --git a/vhdlpp/compiler.h b/vhdlpp/compiler.h index 3cd1b820a..477d33928 100644 --- a/vhdlpp/compiler.h +++ b/vhdlpp/compiler.h @@ -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 */ diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index 6f044b2e8..af4fd7a32 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -150,22 +150,35 @@ void ScopeBase::dump_scope(ostream&out) const } // Dump subprograms out << " -- Imported Subprograms" << endl; - for (map::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::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::const_iterator cur = cur_subprograms_.begin() + for (map::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::const_iterator it = indices_->begin(); + it != indices_->end(); ++it) { + (*it)->dump(out, indent+6); + } + } } void ExpNameALL::dump(ostream&out, int indent) const diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index 49e19242e..d52fa4d11 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -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*ExpAttribute::clone_args() const { void ExpAttribute::visit_args(ExprVisitor& func) { + func.down(); + func(this); + if(args_) { - for(list::iterator it = args_->begin(); + for(list::iterator it = args_->begin(); it != args_->end(); ++it) { - func(*it); - } + (*it)->visit(func); + } } + + func.up(); } ExpObjAttribute::ExpObjAttribute(ExpName*base, perm_string name, list*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*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*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::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*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::iterator it = options_.begin(); - it != options_.end(); ++it) { - (*it)->visit(func); - } - + func.down(); func(this); + + for(std::list::iterator it = options_.begin(); + it != options_.end(); ++it) + (*it)->visit(func); + + func.up(); } ExpConditional::case_t::case_t(Expression*cond, std::list*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::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::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*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*indices) +: prefix_(prefix), name_(nn), indices_(indices) { - ivl_assert(*this, !msb || msb != lsb); } ExpName::~ExpName() { - delete index_; - delete lsb_; + if(indices_) { + for(list::iterator it = indices_->begin(); + it != indices_->end(); ++it) { + delete *it; + } + + delete indices_; + } +} + +Expression*ExpName::clone() const { + list*new_indices = NULL; + + if(indices_) { + new_indices = new list(); + + for(list::const_iterator it = indices_->begin(); + it != indices_->end(); ++it) { + new_indices->push_back((*it)->clone()); + } + } + + return new ExpName(static_cast(safe_clone(prefix_.get())), + name_, new_indices); +} + +void ExpName::add_index(std::list*idx) +{ + if(!indices_) + indices_ = new list(); + + 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::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::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::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(); +} diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index 7ad596e23..b1b6ae244 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -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 # include # include +# include 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*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& 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& 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*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*indices = NULL); + virtual ~ExpName(); public: // Base methods - Expression*clone() const { - return new ExpName(static_cast(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*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&indices, int&data_size); + list&indices, int&data_size) const; bool check_const_array_workaround_(const VTypeArray*arr, ScopeBase*scope, list&indices, int&data_size) const; @@ -753,19 +770,20 @@ class ExpName : public Expression { list&indices, int&data_size) const; int emit_workaround_(ostream&out, Entity*ent, ScopeBase*scope, - const list&indices, int field_size); + const list&indices, int field_size) const; private: + Expression*index(unsigned int number) const; + std::auto_ptr prefix_; perm_string name_; - Expression*index_; - Expression*lsb_; + std::list*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(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 */ diff --git a/vhdlpp/expression_debug.cc b/vhdlpp/expression_debug.cc index c2bc38125..feaaf9510 100644 --- a/vhdlpp/expression_debug.cc +++ b/vhdlpp/expression_debug.cc @@ -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); +} diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index a84bfbdd9..7888f162a 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -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(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(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::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::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 arg_types; - if(!prog) - prog = library_find_subprogram(name_); + for(vector::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 arg_types; + for(vector::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 (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 (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(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(element_type)) { + element_type = pref_array->basic_type(false); + ivl_assert(*this, element_type); + type_changed = true; + } } - if (const VTypeArray*pref_array = dynamic_cast (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::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(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; } diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 8a22c5500..f490cf4dd 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -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 element_map; - choice_element*element_other = 0; + map 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::iterator last = options_.end(); + list::const_iterator last = options_.end(); --last; - for (list::iterator cur = options_.begin() + for (list::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 (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::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& indices, int& data_size) + list& indices, int& data_size) const { Expression*exp = NULL; bool wrkand_required = false; const VType*type = NULL; + Expression*idx = index(0); + ExpRange*range = dynamic_cast(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(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(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&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(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& indices, int field_size) + const list& 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; } diff --git a/vhdlpp/expression_evaluate.cc b/vhdlpp/expression_evaluate.cc index 577defb8b..97a1e4470 100644 --- a/vhdlpp/expression_evaluate.cc +++ b/vhdlpp/expression_evaluate.cc @@ -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; } } diff --git a/vhdlpp/expression_stream.cc b/vhdlpp/expression_stream.cc index b62225dd3..43756922a 100644 --- a/vhdlpp/expression_stream.cc +++ b/vhdlpp/expression_stream.cc @@ -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::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); +} diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index f10b60404..fb015feab 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -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 * * 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*params) { - SubprogramHeader*subp = NULL; + SubprogramHeader*subp; map::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::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()); diff --git a/vhdlpp/library.h b/vhdlpp/library.h index 7fb95851e..5596db870 100644 --- a/vhdlpp/library.h +++ b/vhdlpp/library.h @@ -19,15 +19,18 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -class SubprogramHeader; +#include -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*params); #endif /* IVL_library_H */ diff --git a/vhdlpp/package.cc b/vhdlpp/package.cc index 40730f026..c8ff5b466 100644 --- a/vhdlpp/package.cc +++ b/vhdlpp/package.cc @@ -24,6 +24,8 @@ # include "parse_misc.h" # include "std_types.h" # include "ivl_assert.h" +# include +# include Package::Package(perm_string n, const ActiveScope&ref) : Scope(ref), name_(n) @@ -45,9 +47,15 @@ int Package::elaborate() { int errors = 0; - for (map::const_iterator cur = cur_subprograms_.begin() - ; cur != cur_subprograms_.end() ; ++cur) { - errors += cur->second->elaborate(); + for (map::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::const_iterator cur = use_types_.begin() ; cur != use_types_.end() ; ++cur) { - const VTypeDef*def = dynamic_cast (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::const_iterator cur = cur_types_.begin() ; cur != cur_types_.end() ; ++cur) { - const VTypeDef*def = dynamic_cast (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::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(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::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(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::const_iterator cur = cur_constants_.begin() @@ -134,10 +116,15 @@ void Package::write_to_stream(ostream&fd) const fd << ";" << endl; } - for (map::const_iterator cur = cur_subprograms_.begin() + for (map::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::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::const_iterator cur = cur_subprograms_.begin() + for (map::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; } diff --git a/vhdlpp/package.h b/vhdlpp/package.h index 3f75c8820..7ae45120a 100644 --- a/vhdlpp/package.h +++ b/vhdlpp/package.h @@ -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; diff --git a/vhdlpp/package_emit.cc b/vhdlpp/package_emit.cc index 77d314231..962f68a65 100644 --- a/vhdlpp/package_emit.cc +++ b/vhdlpp/package_emit.cc @@ -20,8 +20,9 @@ # include "package.h" # include "subprogram.h" -# include # include "ivl_assert.h" +# include +# include using namespace std; @@ -64,14 +65,22 @@ int Package::emit_package(ostream&fd) const //} fd << "package \\" << name() << " ;" << endl; - for (map::const_iterator cur = cur_subprograms_.begin() + for (map::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; diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index dbc561867..82ccde7e3 100644 --- a/vhdlpp/parse.y +++ b/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 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*ports) %type concurrent_statement component_instantiation_statement %type concurrent_conditional_signal_assignment %type concurrent_signal_assignment_statement concurrent_simple_signal_assignment +%type concurrent_assertion_statement %type for_generate_statement generate_statement if_generate_statement %type process_statement selected_signal_assignment %type architecture_statement_part generate_statement_body @@ -330,7 +332,7 @@ static void touchup_interface_for_functions(std::list*ports) %type expression factor primary relation %type expression_logical expression_logical_and expression_logical_or %type expression_logical_xnor expression_logical_xor -%type name prefix selected_name +%type name prefix selected_name indexed_name %type shift_expression signal_declaration_assign_opt %type simple_expression simple_expression_2 term %type variable_declaration_assign_opt waveform_element interface_element_expression @@ -352,7 +354,7 @@ static void touchup_interface_for_functions(std::list*ports) %type element_declaration element_declaration_list %type architecture_body_start package_declaration_start -%type package_body_start +%type package_body_start process_start %type identifier_opt identifier_colon_opt logical_name suffix instantiated_unit %type logical_name_list identifier_list @@ -376,7 +378,7 @@ static void touchup_interface_for_functions(std::list*ports) %type if_statement_elsif_list if_statement_elsif_list_opt %type else_when_waveform selected_waveform -%type else_when_waveforms selected_waveform_list +%type else_when_waveforms else_when_waveforms_opt selected_waveform_list %type function_specification procedure_specification %type 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::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 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 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*options; + options = $6 ? $6 : new std::list; + options->push_front(new ExpConditional::case_t($5, $3)); - ExpName*name = dynamic_cast ($1); - assert(name); - SignalAssignment*tmpa = new SignalAssignment(name, tmp); - FILE_NAME(tmpa, @1); + ExpName*name = dynamic_cast($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 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($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 ($1); - tmp->set_range($3->msb(), $3->lsb()); - $$ = tmp; - } - | selected_name '(' expression ')' - { ExpName*tmp = dynamic_cast ($1); - tmp->set_range($3, NULL); - $$ = tmp; + | indexed_name '(' expression_list ')' + { ExpName*name = dynamic_cast($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($1); + ExpName*base = dynamic_cast($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($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($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::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($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; } ; diff --git a/vhdlpp/parse_misc.cc b/vhdlpp/parse_misc.cc index cc9de0a1e..eefe5296b 100644 --- a/vhdlpp/parse_misc.cc +++ b/vhdlpp/parse_misc.cc @@ -29,6 +29,7 @@ # include "compiler.h" # include # include +# include 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; +} diff --git a/vhdlpp/parse_misc.h b/vhdlpp/parse_misc.h index 195264298..d15a8d445 100644 --- a/vhdlpp/parse_misc.h +++ b/vhdlpp/parse_misc.h @@ -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*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 */ diff --git a/vhdlpp/scope.cc b/vhdlpp/scope.cc index 5084986a3..785ab1d98 100644 --- a/vhdlpp/scope.cc +++ b/vhdlpp/scope.cc @@ -24,56 +24,30 @@ # include "entity.h" # include "std_funcs.h" # include "std_types.h" +# include "compiler.h" # include # include # include +# include +# include # include +# include 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 >( - old_signals_, old_signals_.end()) - ); - merge(ref.old_variables_.begin(), ref.old_variables_.end(), - ref.new_variables_.begin(), ref.new_variables_.end(), - insert_iterator >( - old_variables_, old_variables_.end()) - ); - merge(ref.old_components_.begin(), ref.old_components_.end(), - ref.new_components_.begin(), ref.new_components_.end(), - insert_iterator >( - 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::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::iterator cur = cur_subprograms_.begin() + ; cur != cur_subprograms_.end() ; ++cur) { + delete_all(cur->second); + } +} + +ScopeBase*ScopeBase::find_scope(perm_string name) const +{ + map::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::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::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::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::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::const_iterator cur; + map::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::const_iterator cur = that->cur_subprograms_.begin() + for (map::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*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::const_iterator cur; + + cur = use_subprograms_.find(name); + if (cur != use_subprograms_.end()) + copy(cur->second.begin(), cur->second.end(), + front_insert_iterator(l)); + + cur = cur_subprograms_.find(name); + if(cur != cur_subprograms_.end()) + copy(cur->second.begin(), cur->second.end(), + front_insert_iterator(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_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 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::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 >( + old_signals_, old_signals_.end()) + ); + merge(par->old_variables_.begin(), par->old_variables_.end(), + par->new_variables_.begin(), par->new_variables_.end(), + insert_iterator >( + old_variables_, old_variables_.end()) + ); + merge(par->old_components_.begin(), par->old_components_.end(), + par->new_components_.begin(), par->new_components_.end(), + insert_iterator >( + old_components_, old_components_.end()) + ); + merge(par->use_types_.begin(), par->use_types_.end(), + par->cur_types_.begin(), par->cur_types_.end(), + insert_iterator >( + use_types_, use_types_.end()) + ); + merge(par->use_subprograms_.begin(), par->use_subprograms_.end(), + par->cur_subprograms_.begin(), par->cur_subprograms_.end(), + insert_iterator >( + use_subprograms_, use_subprograms_.end()) + ); +} diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index df1f1daba..5f88b384c 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -36,6 +36,8 @@ class SubprogramHeader; class VType; class SequentialStmt; +typedef list SubHeaderList; + template 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::iterator it; + { map::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*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 use_constants_; //imported constants std::map cur_constants_; //current constants - std::map use_subprograms_; //imported - std::map cur_subprograms_; //current + std::map use_subprograms_; //imported + std::map cur_subprograms_; //current + + std::map scopes_; std::list use_enums_; @@ -146,20 +162,30 @@ class ScopeBase { std::list 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 ::*" 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::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 incomplete_types; private: - // If this is a package body, then there is a Package header - // already declared. - Package*package_header_; - Entity*context_entity_; }; diff --git a/vhdlpp/sequential.h b/vhdlpp/sequential.h index ce68bcc3e..13a3f5947 100644 --- a/vhdlpp/sequential.h +++ b/vhdlpp/sequential.h @@ -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_; diff --git a/vhdlpp/sequential_debug.cc b/vhdlpp/sequential_debug.cc index 7abb63d6f..ac4096568 100644 --- a/vhdlpp/sequential_debug.cc +++ b/vhdlpp/sequential_debug.cc @@ -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); + } } diff --git a/vhdlpp/sequential_elaborate.cc b/vhdlpp/sequential_elaborate.cc index 98b8766c0..84a48f55b 100644 --- a/vhdlpp/sequential_elaborate.cc +++ b/vhdlpp/sequential_elaborate.cc @@ -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::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::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(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 arg_types; + if(param_list_) { + for(list::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::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); diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index 0431a1f53..25dc6f60d 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -26,9 +26,11 @@ # include "package.h" # include "compiler.h" # include "subprogram.h" +# include "std_types.h" # include # include # include +# include # include 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::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::vectorparams; + vectorargv; + 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::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 (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::max()) {} + + void operator() (Expression*s) { + if(!dynamic_cast(s)) { + if(level() > level_lock_) + return; + + if(dynamic_cast(s)) { + level_lock_ = level(); + } else { + level_lock_ = numeric_limits::max(); + } + + const VType*type = s->probe_type(ent_, scope_); + + if(dynamic_cast(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); diff --git a/vhdlpp/std_funcs.cc b/vhdlpp/std_funcs.cc index 5b875d98f..fa417904e 100644 --- a/vhdlpp/std_funcs.cc +++ b/vhdlpp/std_funcs.cc @@ -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 std_subprograms; +static std::map 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(); + : SubprogramStdHeader(perm_string::literal("to_integer"), NULL, &primitive_REAL) { + ports_ = new list(); ports_->push_back(new InterfacePort(&primitive_INTEGER)); } - bool is_std() const { return true; } - int emit_name(const std::vector&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(); - 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(); + 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&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(); - 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(); + 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(arg_type); - const VTypePrimitive*prim = dynamic_cast(arg_type); + + while(const VTypeDef*tdef = dynamic_cast(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(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(); - 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&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*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*fn_unsigned_args = new std::list(); - fn_unsigned_args->push_back(new InterfacePort(&primitive_INTEGER)); - fn_unsigned = new SubprogramBuiltin(perm_string::literal("unsigned"), + args = new list(); + 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(); + 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*fn_integer_args = new std::list(); - fn_integer_args->push_back(new InterfacePort(&primitive_INTEGER)); - fn_integer = new SubprogramBuiltin(perm_string::literal("integer"), + args = new list(); + 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*fn_std_logic_vector_args = new std::list(); - 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(); + 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(); + 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(); + 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(); + 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(); + 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(); + 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*fn_rising_edge_args = new std::list(); - fn_rising_edge_args->push_back(new InterfacePort(&primitive_STDLOGIC)); - fn_rising_edge = new SubprogramBuiltin(perm_string::literal("rising_edge"), + args = new list(); + 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*fn_falling_edge_args = new std::list(); - fn_falling_edge_args->push_back(new InterfacePort(&primitive_STDLOGIC)); - fn_falling_edge = new SubprogramBuiltin(perm_string::literal("falling_edge"), + args = new list(); + 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*fn_or_reduce_args = new std::list(); - fn_or_reduce_args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR)); - fn_or_reduce = new SubprogramBuiltin(perm_string::literal("or_reduce"), + args = new list(); + 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*fn_and_reduce_args = new std::list(); - fn_and_reduce_args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR)); - fn_and_reduce = new SubprogramBuiltin(perm_string::literal("and_reduce"), + args = new list(); + 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*fn_to_unsigned_args = new std::list(); - 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(); + 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(); + 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(); + 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*fn_file_open_args = new std::list(); - 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(); + 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(); + 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*fn_file_close_args = new std::list(); - 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(); + 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*fn_readline_args = new std::list(); - 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(); + 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*fn_writeline_args = new std::list(); - 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(); + 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*fn_endfile_args = new std::list(); - fn_endfile_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); - fn_endfile = new SubprogramBuiltin(perm_string::literal("endfile"), + args = new list(); + 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::iterator it = std_subprograms.begin(); - it != std_subprograms.end(); ++it) { - delete it->second; + for(std::map::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::const_iterator cur = std_subprograms.find(name); - if (cur != std_subprograms.end()) - return cur->second; + map::const_iterator cur = std_subprograms.find(name); + if(cur != std_subprograms.end()) + return cur->second; - return NULL; + return SubHeaderList(); } diff --git a/vhdlpp/std_funcs.h b/vhdlpp/std_funcs.h index c966f6591..f3a904d44 100644 --- a/vhdlpp/std_funcs.h +++ b/vhdlpp/std_funcs.h @@ -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 */ diff --git a/vhdlpp/std_types.cc b/vhdlpp/std_types.cc index 9bb9744dd..51f6eaa2d 100644 --- a/vhdlpp/std_types.cc +++ b/vhdlpp/std_types.cc @@ -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 (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 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); diff --git a/vhdlpp/std_types.h b/vhdlpp/std_types.h index b00dd503f..8a91890a3 100644 --- a/vhdlpp/std_types.h +++ b/vhdlpp/std_types.h @@ -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; diff --git a/vhdlpp/subprogram.cc b/vhdlpp/subprogram.cc index 80839b557..bd7d832cc 100644 --- a/vhdlpp/subprogram.cc +++ b/vhdlpp/subprogram.cc @@ -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*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(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 arguments, ScopeBase*scope) const { assert(arguments.size() == ports_->size()); @@ -233,7 +257,7 @@ SubprogramHeader*SubprogramHeader::make_instance(std::vector 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*ports, const VType*return_type) - : SubprogramHeader(vhdl_name, ports, return_type), sv_name_(sv_name) -{ -} - -SubprogramBuiltin::~SubprogramBuiltin() -{ -} diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h index a07570fac..08473239e 100644 --- a/vhdlpp/subprogram.h +++ b/vhdlpp/subprogram.h @@ -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*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&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&, + virtual int emit_name(const std::vector&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*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*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*ports, const VType*return_type); - ~SubprogramBuiltin(); - - bool is_std() const { return true; } + std::list*ports, const VType*return_type) : + SubprogramStdHeader(vhdl_name, ports, return_type), sv_name_(sv_name) {} + ~SubprogramBuiltin() {} int emit_name(const std::vector&, 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&arg_types); + #endif /* IVL_subprogram_H */ diff --git a/vhdlpp/subprogram_emit.cc b/vhdlpp/subprogram_emit.cc index 907550475..2dab34a89 100644 --- a/vhdlpp/subprogram_emit.cc +++ b/vhdlpp/subprogram_emit.cc @@ -21,6 +21,7 @@ # include "subprogram.h" # include "sequential.h" # include "vtype.h" +# include "package.h" # include using namespace std; @@ -97,6 +98,22 @@ int SubprogramHeader::emit_package(ostream&fd) const return errors; } +int SubprogramHeader::emit_full_name(const std::vector&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(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&, std::ostream&out, Entity*, ScopeBase*) const { @@ -124,3 +141,23 @@ int SubprogramBuiltin::emit_name(const std::vector&, out << sv_name_; return 0; } + +void emit_subprogram_sig(ostream&out, perm_string name, + const list&arg_types) +{ + out << name << "("; + bool first = true; + for(list::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 << ""; + } + out << ")"; +} diff --git a/vhdlpp/vsignal.cc b/vhdlpp/vsignal.cc index 68cec4c4a..ab949d7e1 100644 --- a/vhdlpp/vsignal.cc +++ b/vhdlpp/vsignal.cc @@ -22,6 +22,7 @@ # include "vsignal.h" # include "expression.h" # include "vtype.h" +# include "std_types.h" # include 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(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; diff --git a/vhdlpp/vsignal.h b/vhdlpp/vsignal.h index 6aa225d14..9beda6cef 100644 --- a/vhdlpp/vsignal.h +++ b/vhdlpp/vsignal.h @@ -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_; } diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index cc310ad90..7c5ec3aac 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -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 */ diff --git a/vhdlpp/vtype_elaborate.cc b/vhdlpp/vtype_elaborate.cc index b3b4cfd9d..e32d4d28e 100644 --- a/vhdlpp/vtype_elaborate.cc +++ b/vhdlpp/vtype_elaborate.cc @@ -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::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; +} diff --git a/vhdlpp/vtype_emit.cc b/vhdlpp/vtype_emit.cc index c33c68304..8327af50c 100644 --- a/vhdlpp/vtype_emit.cc +++ b/vhdlpp/vtype_emit.cc @@ -98,9 +98,21 @@ int VTypeArray::emit_with_dims_(std::ostream&out, bool packed, perm_string name) list dims; const VTypeArray*cur = this; - while (const VTypeArray*sub = dynamic_cast (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(el_type)) { + el_type = tdef->peek_definition(); + } + + if(const VTypeArray*sub = dynamic_cast(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(type_)) - out << (reg_flag ? "reg " : "wire "); - - if(dynamic_cast(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 diff --git a/vhdlpp/vtype_match.cc b/vhdlpp/vtype_match.cc index 86c8f90ff..a4a49b1b5 100644 --- a/vhdlpp/vtype_match.cc +++ b/vhdlpp/vtype_match.cc @@ -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(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(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(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; } diff --git a/vhdlpp/vtype_stream.cc b/vhdlpp/vtype_stream.cc index 96d9eff4d..2869d6772 100644 --- a/vhdlpp/vtype_stream.cc +++ b/vhdlpp/vtype_stream.cc @@ -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; +} diff --git a/vpi/Makefile.in b/vpi/Makefile.in index 4a5502902..aebdb70b2 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -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 diff --git a/vpi/vhdl_sys.sft b/vpi/vhdl_sys.sft index d0d452212..86903476f 100644 --- a/vpi/vhdl_sys.sft +++ b/vpi/vhdl_sys.sft @@ -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 diff --git a/vpi/vhdl_table.c b/vpi/vhdl_table.c index fdbb68829..64cfe0386 100644 --- a/vpi/vhdl_table.c +++ b/vpi/vhdl_table.c @@ -21,6 +21,7 @@ # include "vpi_user.h" # include # include "ivl_alloc.h" +# include "sys_priv.h" /* * The $ivlh_attribute_event implements the VHDL '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); diff --git a/vpi/vhdl_textio.c b/vpi/vhdl_textio.c index e6a9a8411..3892ef5b7 100644 --- a/vpi/vhdl_textio.c +++ b/vpi/vhdl_textio.c @@ -48,6 +48,7 @@ # include # include # include +# include # 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); diff --git a/vvp/part.cc b/vvp/part.cc index 930e51868..d9ec018b3 100644 --- a/vvp/part.cc +++ b/vvp/part.cc @@ -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); diff --git a/vvp/part.h b/vvp/part.h index 445cc24f5..c0459ee2d 100644 --- a/vvp/part.h +++ b/vvp/part.h @@ -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: