diff --git a/driver/iverilog.man.in b/driver/iverilog.man.in index bf7d986be..edc967d11 100644 --- a/driver/iverilog.man.in +++ b/driver/iverilog.man.in @@ -384,6 +384,11 @@ The function returns an integer. The function returns a vector with the given width, and is signed or unsigned according to the flag. +.TP 8 +.B vpiSysFuncString +The function returns a string. This is an Icarus-specific extension, not +available in the VPI standard. + .SH "COMMAND FILES" The command file allows the user to place source file names and certain command line switches into a text file instead of on a long diff --git a/elab_expr.cc b/elab_expr.cc index cb0be36ca..d4394c1cc 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -2838,7 +2838,7 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope, concat->set(idx, parms[off+idx]); } - if (wid_sum == 0) { + if (wid_sum == 0 && expr_type_ != IVL_VT_STRING) { cerr << get_fileline() << ": error: Concatenation/replication " << "may not have zero width in this context." << endl; des->errors += 1; diff --git a/sv_vpi_user.h b/sv_vpi_user.h index 47a5a4296..c4f96addd 100644 --- a/sv_vpi_user.h +++ b/sv_vpi_user.h @@ -75,6 +75,10 @@ EXTERN_C_START /********* task/function properties **********/ #define vpiOtherFunc 6 +/* Icarus-specific function type to use string as the return type */ +#define vpiStringFunc 10 +#define vpiSysFuncString vpiSysFuncString + EXTERN_C_END #endif /* SV_VPI_USER_H */ diff --git a/synth2.cc b/synth2.cc index 44f7e07f6..3d3805891 100644 --- a/synth2.cc +++ b/synth2.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -103,6 +103,14 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope, NetNet*rsig = rval_->synthesize(des, scope, rval_); assert(rsig); + if (lval_->word() && ! dynamic_cast(lval_->word())) { + cerr << get_fileline() << ": sorry: assignment to variable " + "location in memory is not currently supported in " + "synthesis." << endl; + des->errors += 1; + return false; + } + NetNet*lsig = lval_->sig(); if (!lsig) { cerr << get_fileline() << ": error: " @@ -218,6 +226,8 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope, rsig = tmp; } + rsig = crop_to_width(des, rsig, lsig->vector_width()); + if (nex_out.pin_count() > 1) { NexusSet tmp_set; nex_output(tmp_set); @@ -1411,6 +1421,16 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, are used to collect the outputs from the substatement for the inputs of the FF bank. */ NetBus tmp_out (scope, tmp_set.size()); + for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) { + unsigned ptr = nex_map.find_nexus(tmp_set[idx]); + ivl_assert(*this, ptr < nex_out.pin_count()); + if (nex_out.pin(ptr).is_linked()) { + cerr << get_fileline() << ": sorry: multiple statements " + "assigning to the same flip-flop are not yet " + "supported in synthesis." << endl; + return false; + } + } /* Create a temporary ff_ce (FF clock-enable) that accounts for the subset of outputs that this diff --git a/sys_funcs.cc b/sys_funcs.cc index 3e2b26a51..bb1ccd8bc 100644 --- a/sys_funcs.cc +++ b/sys_funcs.cc @@ -204,6 +204,17 @@ int load_sys_func_table(const char*path) continue; } + if (strcmp(stype,"vpiSysFuncString") == 0) { + cell = new struct sfunc_return_type_cell; + cell->name = lex_strings.add(name); + cell->type = IVL_VT_STRING; + cell->wid = 0; // string is a dynamic length type + cell->signed_flag = false; + cell->next = sfunc_stack; + sfunc_stack = cell; + continue; + } + fprintf(stderr, "%s:%s: Unknown type: %s\n", path, name, stype); } diff --git a/tgt-vvp/draw_vpi.c b/tgt-vvp/draw_vpi.c index 14e18e53a..b8503a537 100644 --- a/tgt-vvp/draw_vpi.c +++ b/tgt-vvp/draw_vpi.c @@ -519,3 +519,14 @@ void draw_vpi_rfunc_call(ivl_expr_t fnet) draw_vpi_taskfunc_args(call_string, 0, fnet); } + +void draw_vpi_sfunc_call(ivl_expr_t fnet) +{ + char call_string[1024]; + + sprintf(call_string, " %%vpi_func/s %u %u \"%s\"", + ivl_file_table_index(ivl_expr_file(fnet)), + ivl_expr_lineno(fnet), ivl_expr_name(fnet)); + + draw_vpi_taskfunc_args(call_string, 0, fnet); +} diff --git a/tgt-vvp/eval_condit.c b/tgt-vvp/eval_condit.c index 59c7a88c6..2e46894ef 100644 --- a/tgt-vvp/eval_condit.c +++ b/tgt-vvp/eval_condit.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2014-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -76,8 +76,8 @@ static int draw_condition_binary_compare(ivl_expr_t expr) %cmp instruction. */ if (ivl_expr_width(le)==use_wid && test_immediate_vec4_ok(le)) { ivl_expr_t tmp = le; - re = le; - le = tmp; + le = re; + re = tmp; } draw_eval_vec4(le); diff --git a/tgt-vvp/eval_string.c b/tgt-vvp/eval_string.c index 92d702058..8cdb26338 100644 --- a/tgt-vvp/eval_string.c +++ b/tgt-vvp/eval_string.c @@ -163,6 +163,12 @@ static void string_ex_pop(ivl_expr_t expr) fprintf(vvp_out, " %%qpop/%s/str v%p_0;\n", fb, ivl_expr_signal(arg)); } +static void draw_sfunc_string(ivl_expr_t expr) +{ + assert(ivl_expr_value(expr) == IVL_VT_STRING); + draw_vpi_sfunc_call(expr); +} + void draw_eval_string(ivl_expr_t expr) { @@ -195,7 +201,7 @@ void draw_eval_string(ivl_expr_t expr) else if (strcmp(ivl_expr_name(expr), "$ivl_darray_method$pop_front")==0) string_ex_pop(expr); else - fallback_eval(expr); + draw_sfunc_string(expr); break; case IVL_EX_UFUNC: diff --git a/tgt-vvp/vvp_priv.h b/tgt-vvp/vvp_priv.h index 3a4c17bfc..fdffa81b8 100644 --- a/tgt-vvp/vvp_priv.h +++ b/tgt-vvp/vvp_priv.h @@ -133,6 +133,7 @@ extern void draw_vpi_task_call(ivl_statement_t net); extern void draw_vpi_func_call(ivl_expr_t expr); extern void draw_vpi_rfunc_call(ivl_expr_t expr); +extern void draw_vpi_sfunc_call(ivl_expr_t expr); extern void draw_class_in_scope(ivl_type_t classtype); diff --git a/vhdlpp/architec.cc b/vhdlpp/architec.cc index 57b885feb..2f1cea235 100644 --- a/vhdlpp/architec.cc +++ b/vhdlpp/architec.cc @@ -137,7 +137,7 @@ GenerateStatement::~GenerateStatement() } ForGenerate::ForGenerate(perm_string gname, perm_string genvar, - prange_t*rang, std::list&s) + ExpRange*rang, std::list&s) : GenerateStatement(gname, s), genvar_(genvar), lsb_(rang->lsb()), msb_(rang->msb()) { diff --git a/vhdlpp/architec.h b/vhdlpp/architec.h index 435ad3639..d33a33e57 100644 --- a/vhdlpp/architec.h +++ b/vhdlpp/architec.h @@ -33,7 +33,7 @@ class GenerateStatement; class SequentialStmt; class Signal; class named_expr_t; -class prange_t; +class ExpRange; /* * The Architecture class carries the contents (name, statements, @@ -142,7 +142,7 @@ class ForGenerate : public GenerateStatement { public: ForGenerate(perm_string gname, perm_string genvar, - prange_t*rang, std::list&s); + ExpRange*rang, std::list&s); ~ForGenerate(); int elaborate(Entity*ent, Architecture*arc); diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index 7430bae83..cfedeb467 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -21,6 +21,7 @@ # include "entity.h" # include "expression.h" # include "sequential.h" +# include "subprogram.h" # include # include @@ -59,6 +60,11 @@ int Architecture::elaborate(Entity*entity) cur->second->elaborate_init_expr(entity, this); } + // Elaborate subprograms + for (map::const_iterator cur = cur_subprograms_.begin() + ; cur != cur_subprograms_.end() ; ++cur) { + errors += cur->second->elaborate(); + } // Create 'initial' and 'final' blocks for implicit // initalization and clean-up actions if(!initializers_.empty()) @@ -222,7 +228,7 @@ int ProcessStatement::rewrite_as_always_edge_(Entity*, Architecture*) } // If operand1 is not an 'event attribute, I give up. - const ExpAttribute*op1 = dynamic_cast(op1_raw); + const ExpObjAttribute*op1 = dynamic_cast(op1_raw); if (op1 == 0) return -1; if (op1->peek_attribute() != "event") diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index 22fb312a6..6f044b2e8 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -101,7 +101,7 @@ void ComponentBase::dump_ports(ostream&out, int indent) const } } -void Scope::dump_scope(ostream&out) const +void ScopeBase::dump_scope(ostream&out) const { // Dump types out << " -- imported types" << endl; @@ -251,9 +251,16 @@ void ExpAggregate::choice_t::dump(ostream&out, int indent) const out << setw(indent) << "" << "?choice_t?" << endl; } -void ExpAttribute::dump(ostream&out, int indent) const +void ExpTypeAttribute::dump(ostream&out, int indent) const { - out << setw(indent) << "" << "Attribute " << name_ + out << setw(indent) << "" << "Attribute (type-related) " << name_ + << " at " << get_fileline() << endl; + base_->show(out); +} + +void ExpObjAttribute::dump(ostream&out, int indent) const +{ + out << setw(indent) << "" << "Attribute (object-related) " << name_ << " at " << get_fileline() << endl; base_->dump(out, indent+4); } @@ -442,13 +449,6 @@ void named_expr_t::dump(ostream&out, int indent) const expr_->dump(out, indent); } -void prange_t::dump(ostream&out, int indent) const -{ - left_->dump(out, indent); - out << setw(indent) << "" << (direction_ ? "downto" : "to"); - right_->dump(out, indent); -} - ostream& Expression::dump_inline(ostream&out) const { out << typeid(*this).name(); diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index baa0ce554..49e19242e 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -54,29 +54,88 @@ bool Expression::symbolic_compare(const Expression*) const return false; } -ExpAttribute::ExpAttribute(ExpName*bas, perm_string nam) -: base_(bas), name_(nam) +ExpAttribute::ExpAttribute(perm_string nam, list*args) +: name_(nam), args_(args) { } ExpAttribute::~ExpAttribute() { - /* Different attributes can point to the same base so we cannot delete this here. - * Look at the vhdl_range test with valgrind to see this issue. */ -// delete base_; + if(args_) { + for(list::iterator it = args_->begin(); + it != args_->end(); ++it) { + delete *it; + } + } + + delete args_; } -Expression*ExpAttribute::clone() const -{ - return new ExpAttribute(static_cast(base_->clone()), name_); +list*ExpAttribute::clone_args() const { + list*new_args = NULL; + + if(args_) { + for(list::iterator it = args_->begin(); + it != args_->end(); ++it) { + new_args->push_back((*it)->clone()); + } + } + + return new_args; } -void ExpAttribute::visit(ExprVisitor& func) +void ExpAttribute::visit_args(ExprVisitor& func) { + if(args_) { + for(list::iterator it = args_->begin(); + it != args_->end(); ++it) { + func(*it); + } + } +} + +ExpObjAttribute::ExpObjAttribute(ExpName*base, perm_string name, list*args) +: ExpAttribute(name, args), base_(base) +{ +} + +ExpObjAttribute::~ExpObjAttribute() +{ + delete base_; +} + +Expression*ExpObjAttribute::clone() const +{ + return new ExpObjAttribute(static_cast(base_->clone()), + name_, clone_args()); +} + +void ExpObjAttribute::visit(ExprVisitor& func) +{ + visit_args(func); base_->visit(func); func(this); } +ExpTypeAttribute::ExpTypeAttribute(const VType*base, perm_string name, list*args) +: ExpAttribute(name, args), base_(base) +{ +} + +Expression*ExpTypeAttribute::clone() const +{ + return new ExpTypeAttribute(base_, name_, clone_args()); +} + +void ExpTypeAttribute::visit(ExprVisitor& func) +{ + visit_args(func); + func(this); +} + +const perm_string ExpAttribute::LEFT = perm_string::literal("left"); +const perm_string ExpAttribute::RIGHT = perm_string::literal("right"); + ExpBinary::ExpBinary(Expression*op1, Expression*op2) : operand1_(op1), operand2_(op2) { @@ -88,14 +147,14 @@ ExpBinary::~ExpBinary() delete operand2_; } -bool ExpBinary::eval_operand1(ScopeBase*scope, int64_t&val) const +bool ExpBinary::eval_operand1(Entity*ent, ScopeBase*scope, int64_t&val) const { - return operand1_->evaluate(scope, val); + return operand1_->evaluate(ent, scope, val); } -bool ExpBinary::eval_operand2(ScopeBase*scope, int64_t&val) const +bool ExpBinary::eval_operand2(Entity*ent, ScopeBase*scope, int64_t&val) const { - return operand2_->evaluate(scope, val); + return operand2_->evaluate(ent, scope, val); } void ExpBinary::visit(ExprVisitor& func) @@ -192,7 +251,7 @@ ExpAggregate::choice_t::choice_t() { } -ExpAggregate::choice_t::choice_t(prange_t*rang) +ExpAggregate::choice_t::choice_t(ExpRange*rang) : range_(rang) { } @@ -203,7 +262,7 @@ ExpAggregate::choice_t::choice_t(const choice_t&other) expr_.reset(e->clone()); if(other.range_.get()) - range_.reset(new prange_t(*other.range_.get())); + range_.reset(static_cast(other.range_.get()->clone())); } ExpAggregate::choice_t::~choice_t() @@ -221,7 +280,7 @@ Expression*ExpAggregate::choice_t::simple_expression(bool detach_flag) return res; } -prange_t*ExpAggregate::choice_t::range_expressions(void) +ExpRange*ExpAggregate::choice_t::range_expressions(void) { return range_.get(); } @@ -493,7 +552,7 @@ ExpInteger::~ExpInteger() { } -bool ExpInteger::evaluate(ScopeBase*, int64_t&val) const +bool ExpInteger::evaluate(Entity*, ScopeBase*, int64_t&val) const { val = value_; return true; @@ -535,6 +594,7 @@ ExpName::ExpName(perm_string nn, list*indices) 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) @@ -545,6 +605,7 @@ ExpName::ExpName(ExpName*prefix, perm_string nn) ExpName::ExpName(ExpName*prefix, perm_string nn, Expression*msb, Expression*lsb) : prefix_(prefix), name_(nn), index_(msb), lsb_(lsb) { + ivl_assert(*this, !msb || msb != lsb); } ExpName::~ExpName() @@ -712,3 +773,75 @@ double ExpTime::to_fs() const return val; } + +ExpRange::ExpRange(Expression*left, Expression*right, range_dir_t direction) +: left_(left), right_(right), direction_(direction), range_expr_(false), + range_base_(NULL) +{ +} + +ExpRange::ExpRange(ExpName*base, bool reverse_range) +: left_(NULL), right_(NULL), direction_(AUTO), range_expr_(true), + range_base_(base), range_reverse_(reverse_range) +{ +} + +ExpRange::~ExpRange() +{ + delete left_; + delete right_; + delete range_base_; +} + +Expression*ExpRange::clone() const +{ + if(range_expr_) + return new ExpRange(static_cast(range_base_->clone()), range_reverse_); + else + return new ExpRange(left_->clone(), right_->clone(), direction_); +} + +Expression* ExpRange::msb() +{ + ivl_assert(*this, direction() != AUTO); + + switch(direction()) { + case DOWNTO: return left_; + case TO: return right_; + default: return NULL; + } + + return NULL; +} + +Expression* ExpRange::lsb() +{ + ivl_assert(*this, direction() != AUTO); + + switch(direction()) { + case DOWNTO: return right_; + case TO: return left_; + default: return NULL; + } + + return NULL; +} + +Expression*ExpRange::left() +{ + if(range_expr_ && !left_) + // TODO check if it is an object or type + left_ = new ExpObjAttribute(static_cast(range_base_->clone()), + ExpAttribute::LEFT, NULL); + + return left_; +} + +Expression*ExpRange::right() +{ + if(range_expr_ && !right_) + // TODO check if it is an object or type + right_ = new ExpObjAttribute(static_cast(range_base_->clone()), + ExpAttribute::RIGHT, NULL); + return right_; +} diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index eb83474df..7ad596e23 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -29,8 +29,7 @@ # include # include -class prange_t; -class Entity; +class ExpRange; class ScopeBase; class SubprogramHeader; class VType; @@ -107,8 +106,8 @@ class Expression : public LineInfo { // to constant literal values. Return true and set the val // argument if the evaluation works, or return false if it // cannot be done. - virtual bool evaluate(ScopeBase*scope, int64_t&val) const; - virtual bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; + virtual bool evaluate(Entity*, ScopeBase*, int64_t&) const { return false; } + bool evaluate(ScopeBase*scope, int64_t&val) const { return evaluate(NULL, scope, val); } // The symbolic compare returns true if the two expressions // are equal without actually calculating the value. @@ -125,7 +124,7 @@ class Expression : public LineInfo { virtual void dump(ostream&out, int indent = 0) const =0; virtual ostream& dump_inline(ostream&out) const; - // Recursively visits a tree of expressions (useful of complex expressions). + // Recursively visits a tree of expressions (useful for complex expressions). virtual void visit(ExprVisitor& func) { func(this); } protected: @@ -205,8 +204,8 @@ class ExpBinary : public Expression { int emit_operand1(ostream&out, Entity*ent, ScopeBase*scope); int emit_operand2(ostream&out, Entity*ent, ScopeBase*scope); - bool eval_operand1(ScopeBase*scope, int64_t&val) const; - bool eval_operand2(ScopeBase*scope, int64_t&val) const; + bool eval_operand1(Entity*ent, ScopeBase*scope, int64_t&val) const; + bool eval_operand2(Entity*ent, ScopeBase*scope, int64_t&val) const; inline void write_to_stream_operand1(std::ostream&out) const { operand1_->write_to_stream(out); } @@ -239,7 +238,7 @@ class ExpAggregate : public Expression { // Create a named choice explicit choice_t(perm_string name); // discreate_range choice - explicit choice_t(prange_t*ran); + explicit choice_t(ExpRange*ran); choice_t(const choice_t&other); @@ -249,15 +248,15 @@ class ExpAggregate : public Expression { bool others() const; // Return expression if this represents a simple_expression. Expression*simple_expression(bool detach_flag =true); - // Return prange_t if this represents a range_expression - prange_t*range_expressions(void); + // Return ExpRange if this represents a range_expression + ExpRange*range_expressions(void); void write_to_stream(std::ostream&fd); void dump(ostream&out, int indent) const; private: std::auto_ptrexpr_; - std::auto_ptr range_; + std::auto_ptr range_; private: // not implemented choice_t& operator= (const choice_t&); }; @@ -343,7 +342,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); - virtual bool evaluate(ScopeBase*scope, int64_t&val) const; + virtual bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; private: @@ -356,18 +355,60 @@ class ExpArithmetic : public ExpBinary { class ExpAttribute : public Expression { public: - ExpAttribute(ExpName*base, perm_string name); - ~ExpAttribute(); + ExpAttribute(perm_string name,std::list*args); + virtual ~ExpAttribute(); + + inline perm_string peek_attribute() const { return name_; } + + // Constants for the standard attributes + static const perm_string LEFT; + static const perm_string RIGHT; + + protected: + std::list*clone_args() const; + 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; + + perm_string name_; + std::list*args_; +}; + +class ExpObjAttribute : public ExpAttribute { + public: + ExpObjAttribute(ExpName*base, perm_string name, std::list*args); + ~ExpObjAttribute(); Expression*clone() const; - inline perm_string peek_attribute() const { return name_; } inline const ExpName* peek_base() const { return base_; } + int emit(ostream&out, Entity*ent, ScopeBase*scope); 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; + // Some attributes can be evaluated at compile time + bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; + void dump(ostream&out, int indent = 0) const; + void visit(ExprVisitor& func); + + private: + ExpName*base_; +}; + +class ExpTypeAttribute : public ExpAttribute { + public: + ExpTypeAttribute(const VType*base, perm_string name, std::list*args); + // no destructor - VType objects (base_) are shared between many expressions + + Expression*clone() const; + + inline const VType* peek_base() const { return base_; } + int emit(ostream&out, Entity*ent, ScopeBase*scope); + 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; // Some attributes can be evaluated at compile time bool evaluate(ScopeBase*scope, int64_t&val) const; bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; @@ -375,8 +416,7 @@ class ExpAttribute : public Expression { void visit(ExprVisitor& func); private: - ExpName*base_; - perm_string name_; + const VType*base_; }; class ExpBitstring : public Expression { @@ -440,7 +480,6 @@ class ExpConcat : public Expression { 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); - virtual bool evaluate(ScopeBase*scope, int64_t&val) const; bool is_primary(void) const; void dump(ostream&out, int indent = 0) const; void visit(ExprVisitor& func); @@ -583,7 +622,7 @@ class ExpInteger : public Expression { int emit(ostream&out, Entity*ent, ScopeBase*scope); int emit_package(std::ostream&out); bool is_primary(void) const { return true; } - bool evaluate(ScopeBase*scope, int64_t&val) const; + bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; virtual ostream& dump_inline(ostream&out) const; @@ -665,7 +704,6 @@ class ExpName : public Expression { void write_to_stream(std::ostream&fd) const; int emit(ostream&out, Entity*ent, ScopeBase*scope); bool is_primary(void) const; - bool evaluate(ScopeBase*scope, int64_t&val) 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; @@ -773,7 +811,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); - virtual bool evaluate(ScopeBase*scope, int64_t&val) const; + bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; private: @@ -891,7 +929,6 @@ 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); - //bool evaluate(ScopeBase*scope, int64_t&val) const; //bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; @@ -902,6 +939,46 @@ class ExpTime : public Expression { timeunit_t unit_; }; +class ExpRange : public Expression { + public: + typedef enum { DOWNTO, TO, AUTO } range_dir_t; + + // Regular range + ExpRange(Expression*left, Expression*right, range_dir_t direction); + // 'range/'reverse range attribute + ExpRange(ExpName*base, bool reverse_range); + ~ExpRange(); + + Expression*clone() const; + + // Returns the upper boundary + Expression*msb(); + // Returns the lower boundary + Expression*lsb(); + + Expression*left(); + Expression*right(); + + range_dir_t direction() const { return direction_; } + + 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); + void dump(ostream&out, int indent = 0) const; + private: + // Regular range related fields + Expression*left_, *right_; + range_dir_t direction_; + + // 'range/'reverse_range attribute related fields + // Flag to indicate it is a 'range/'reverse_range expression + bool range_expr_; + // Object name to which the attribute is applied + ExpName*range_base_; + // Flag to distinguish between 'range & 'reverse_range + 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); diff --git a/vhdlpp/expression_debug.cc b/vhdlpp/expression_debug.cc index fd52b6875..c2bc38125 100644 --- a/vhdlpp/expression_debug.cc +++ b/vhdlpp/expression_debug.cc @@ -117,3 +117,9 @@ void ExpTime::dump(ostream&out, int indent) const out << setw(indent) << "" << "Time "; write_to_stream(out); } + +void ExpRange::dump(ostream&out, int indent) const +{ + out << setw(indent) << "" << "Range "; + write_to_stream(out); +} diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 29a0e60b3..a84bfbdd9 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -57,7 +57,8 @@ const VType* Expression::fit_type(Entity*ent, ScopeBase*scope, const VTypeArray* return res; } -const VType*ExpName::elaborate_adjust_type_with_range_(Entity*, ScopeBase*scope, const VType*type) +const VType*ExpName::elaborate_adjust_type_with_range_(Entity*ent, ScopeBase*scope, + const VType*type) { // Unfold typedefs while (const VTypeDef*tdef = dynamic_cast(type)) { @@ -76,9 +77,9 @@ const VType*ExpName::elaborate_adjust_type_with_range_(Entity*, ScopeBase*scope, int64_t use_msb, use_lsb; bool flag; - flag = index_->evaluate(scope, use_msb); + flag = index_->evaluate(ent, scope, use_msb); ivl_assert(*this, flag); - flag = lsb_->evaluate(scope, use_lsb); + flag = lsb_->evaluate(ent, scope, use_lsb); ivl_assert(*this, flag); type = new VTypeArray(array->element_type(), use_msb, use_lsb); @@ -216,36 +217,44 @@ int ExpName::elaborate_lval(Entity*ent, ScopeBase*scope, bool is_sequ) const VType*found_type = 0; - if (const InterfacePort*cur = ent->find_port(name_)) { - if (cur->mode != PORT_OUT && cur->mode != PORT_INOUT) { - cerr << get_fileline() << ": error: Assignment to " - "input port " << name_ << "." << endl; - return errors += 1; - } + if (ent) { + if (const InterfacePort*cur = ent->find_port(name_)) { + if (cur->mode != PORT_OUT && cur->mode != PORT_INOUT) { + cerr << get_fileline() << ": error: Assignment to " + "input port " << name_ << "." << endl; + return errors += 1; + } - if (is_sequ) - ent->set_declaration_l_value(name_, is_sequ); + if (is_sequ) + ent->set_declaration_l_value(name_, is_sequ); - found_type = cur->type; + found_type = cur->type; - } else if (ent->find_generic(name_)) { + } else if (ent->find_generic(name_)) { - cerr << get_fileline() << ": error: Assignment to generic " - << name_ << " from entity " - << ent->get_name() << "." << endl; - return 1; + cerr << get_fileline() << ": error: Assignment to generic " + << name_ << " from entity " + << ent->get_name() << "." << endl; + return 1; + } + } - } else if (Signal*sig = scope->find_signal(name_)) { - // Tell the target signal that this may be a sequential l-value. - if (is_sequ) sig->count_ref_sequ(); + if (!found_type && scope) { + if (Signal*sig = scope->find_signal(name_)) { + // Tell the target signal that this may be a sequential l-value. + if (is_sequ) sig->count_ref_sequ(); - found_type = sig->peek_type(); + found_type = sig->peek_type(); - } else if (Variable*var = scope->find_variable(name_)) { - // Tell the target signal that this may be a sequential l-value. - if (is_sequ) var->count_ref_sequ(); + } else if (Variable*var = scope->find_variable(name_)) { + // Tell the target signal that this may be a sequential l-value. + if (is_sequ) var->count_ref_sequ(); - found_type = var->peek_type(); + found_type = var->peek_type(); + + } else if (const InterfacePort*port = scope->find_param(name_)) { + found_type = port->type; + } } if (found_type == 0) { @@ -318,7 +327,8 @@ int ExpName::elaborate_rval(Entity*ent, ScopeBase*scope, const InterfacePort*lva int Expression::elaborate_expr(Entity*, ScopeBase*, const VType*) { - cerr << get_fileline() << ": internal error: I don't know how to elaborate expression type=" << typeid(*this).name() << endl; + cerr << get_fileline() << ": internal error: I don't know how to " + << "elaborate expression type=" << typeid(*this).name() << endl; return 1; } @@ -393,7 +403,7 @@ const VType*ExpAggregate::fit_type(Entity*, ScopeBase*, const VTypeArray*host) c elements_[0]->map_choices(&ce[0]); ivl_assert(*this, ce.size() == 1); - prange_t*prange = ce[0].choice->range_expressions(); + ExpRange*prange = ce[0].choice->range_expressions(); ivl_assert(*this, prange); Expression*use_msb = prange->msb(); @@ -573,23 +583,32 @@ const VType* ExpArithmetic::resolve_operand_types_(const VType*t1, const VType*t return 0; } -const VType* ExpAttribute::probe_type(Entity*ent, ScopeBase*scope) const +int ExpObjAttribute::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) { - base_->probe_type(ent, scope); + const VType*sub_type = base_->probe_type(ent, scope); + return base_->elaborate_expr(ent, scope, sub_type); +} - if (name_ == "length" || name_ == "left" || name_ == "right") { +const VType* ExpObjAttribute::probe_type(Entity*, ScopeBase*) const +{ + if (name_ == "length" || name_ == "left" || name_ == "right") return &primitive_NATURAL; - } + return NULL; +} + +int ExpTypeAttribute::elaborate_expr(Entity*, ScopeBase*, const VType*) +{ + // This is just to mute warnings, there is nothing to elaborate here return 0; } -int ExpAttribute::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) +const VType* ExpTypeAttribute::probe_type(Entity*, ScopeBase*) const { - int errors = 0; - const VType*sub_type = base_->probe_type(ent, scope); - errors += base_->elaborate_expr(ent, scope, sub_type); - return errors; + if(name_ == "image") + return &primitive_STRING; + + return NULL; } const VType*ExpBitstring::fit_type(Entity*, ScopeBase*, const VTypeArray*atype) const @@ -648,8 +667,8 @@ const VType*ExpConcat::fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*at new ExpArithmetic(ExpArithmetic::PLUS, sizes[0], sizes[1]), new ExpInteger(1)); - std::list ranges; - ranges.push_front(new prange_t(size, new ExpInteger(0), true)); + std::list ranges; + ranges.push_front(new ExpRange(size, new ExpInteger(0), ExpRange::DOWNTO)); const VType*array = new VTypeArray(types[1], &ranges); return array; @@ -912,31 +931,31 @@ const VType* ExpName::probe_type(Entity*ent, ScopeBase*scope) const if(ent) { if (const InterfacePort*cur = ent->find_port(name_)) { - ivl_assert(*this, cur->type); - return cur->type; + ivl_assert(*this, cur->type); + return cur->type; } if (const InterfacePort*cur = ent->find_generic(name_)) { - ivl_assert(*this, cur->type); - return cur->type; + ivl_assert(*this, cur->type); + return cur->type; } } if(scope) { if (Signal*sig = scope->find_signal(name_)) - return sig->peek_type(); + return sig->peek_type(); if (Variable*var = scope->find_variable(name_)) - return var->peek_type(); + return var->peek_type(); const VType*type = 0; Expression*cval = 0; if (scope->find_constant(name_, type, cval)) - return type; + return type; Architecture*arc = dynamic_cast(scope); if (arc && (type = arc->probe_genvar_type(name_))) { - return type; + return type; } if (const InterfacePort*port = scope->find_param(name_)) { @@ -1048,6 +1067,19 @@ int ExpTime::elaborate_expr(Entity*, ScopeBase*, const VType*) return 0; } +int ExpRange::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) +{ + int errors = 0; + + if(left_) + errors += left_->elaborate_expr(ent, scope, &primitive_INTEGER); + + if(right_) + errors += right_->elaborate_expr(ent, scope, &primitive_INTEGER); + + return errors; +} + int elaborate_argument(Expression*expr, const SubprogramHeader*subp, int idx, Entity*ent, ScopeBase*scope) { diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 8874da8e6..8a22c5500 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -224,7 +224,7 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, ScopeBase*scope, const VT // If this is a range choice, then calculate the bounds // of the range and scan through the values, mapping the // value to the aggregate_[idx] element. - if (prange_t*range = aggregate_[idx].choice->range_expressions()) { + if (ExpRange*range = aggregate_[idx].choice->range_expressions()) { int64_t begin_val, end_val; if (! range->msb()->evaluate(ent, scope, begin_val)) { @@ -331,13 +331,13 @@ int ExpAggregate::emit_record_(ostream&out, Entity*ent, ScopeBase*scope, const V return errors; } -int ExpAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope) +int ExpObjAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; // Try to evaluate first int64_t val; - if(evaluate(scope, val)) { + if(evaluate(ent, scope, val)) { out << val; return 0; } @@ -365,12 +365,50 @@ int ExpAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope) return errors; } + // Fallback out << "$ivl_attribute("; errors += base_->emit(out, ent, scope); out << ", \"" << name_ << "\")"; return errors; } +int ExpTypeAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope) +{ + int errors = 0; + + // Special case: The image attribute + if (name_=="image") { + if(!args_ || args_->size() != 1) { + out << "/* Invalid 'image attribute */" << endl; + cerr << get_fileline() << ": error: 'image attribute takes " + << "exactly one argument." << endl; + ++errors; + } else { + out << "$sformatf(\""; + + if(base_->type_match(&primitive_INTEGER)) + out << "%0d"; + else if(base_->type_match(&primitive_REAL)) + out << "%f"; + else if(base_->type_match(&primitive_CHARACTER)) + out << "'%c'"; + else if(base_->type_match(&primitive_TIME)) + out << "%+0t"; + + out << "\","; + args_->front()->emit(out, ent, scope); + out << ")"; + } + return errors; + } + + // Fallback + out << "$ivl_attribute("; + errors += base_->emit_def(out, empty_perm_string); + out << ", \"" << name_ << "\")"; + return errors; +} + int ExpArithmetic::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; @@ -453,17 +491,16 @@ int ExpCharacter::emit_primitive_bit_(ostream&out, Entity*, ScopeBase*, int ExpCharacter::emit(ostream&out, Entity*ent, ScopeBase*scope) { const VType*etype = peek_type(); + const VTypeArray*array; + + if (etype != &primitive_CHARACTER && (array = dynamic_cast(etype))) { + etype = array->element_type(); + } if (const VTypePrimitive*use_type = dynamic_cast(etype)) { return emit_primitive_bit_(out, ent, scope, use_type); } - if (const VTypeArray*array = dynamic_cast(etype)) { - if (const VTypePrimitive*use_type = dynamic_cast(array->element_type())) { - return emit_primitive_bit_(out, ent, scope, use_type); - } - } - out << "\"" << value_ << "\""; return 0; } @@ -583,7 +620,10 @@ int ExpFunc::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; - ivl_assert(*this, def_); + if(!def_) { + cerr << get_fileline() << ": error: unknown function: " << name_ << endl; + return 1; + } // If this function has an elaborated definition, and if // that definition is in a package, then include the @@ -909,10 +949,11 @@ bool ExpString::is_primary(void) const int ExpString::emit(ostream& out, Entity*ent, ScopeBase*scope) { + const VTypeArray*arr; const VType*type = peek_type(); assert(type != 0); - if (const VTypeArray*arr = dynamic_cast(type)) { + if (type != &primitive_STRING && (arr = dynamic_cast(type))) { return emit_as_array_(out, ent, scope, arr); } @@ -1028,3 +1069,25 @@ int ExpTime::emit(ostream&out, Entity*, ScopeBase*) return 0; } + +int ExpRange::emit(ostream&out, Entity*ent, ScopeBase*scope) +{ + int errors = 0; + + if(range_expr_) { + out << "$left("; + errors += range_base_->emit(out, ent, scope); + out << "):$right("; + errors += range_base_->emit(out, ent, scope); + out << ")"; + } else if(direction_ == AUTO) { + ivl_assert(*this, false); + out << "/* auto dir */"; + } else { + errors += left_->emit(out, ent, scope); + out << ":"; + errors += right_->emit(out, ent, scope); + } + + return 0; +} diff --git a/vhdlpp/expression_evaluate.cc b/vhdlpp/expression_evaluate.cc index 0d7ef1634..577defb8b 100644 --- a/vhdlpp/expression_evaluate.cc +++ b/vhdlpp/expression_evaluate.cc @@ -25,26 +25,16 @@ # include # include -bool Expression::evaluate(ScopeBase*, int64_t&) const -{ - return false; -} - -bool Expression::evaluate(Entity*, ScopeBase*scope, int64_t&val) const -{ - return evaluate(scope, val); -} - -bool ExpArithmetic::evaluate(ScopeBase*scope, int64_t&val) const +bool ExpArithmetic::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const { int64_t val1, val2; bool rc; - rc = eval_operand1(scope, val1); + rc = eval_operand1(ent, scope, val1); if (rc == false) return false; - rc = eval_operand2(scope, val2); + rc = eval_operand2(ent, scope, val2); if (rc == false) return false; @@ -83,151 +73,110 @@ bool ExpArithmetic::evaluate(ScopeBase*scope, int64_t&val) const return true; } -bool ExpAttribute::evaluate(ScopeBase*scope, int64_t&val) const +bool ExpAttribute::test_array_type(const VType*type) const { - /* Special Case: The array attributes can sometimes be calculated all - the down to a literal integer at compile time, and all it - needs is the type of the base expression. (The base - expression doesn't even need to be evaluated.) */ - if (name_ == "length" || name_ == "right" || name_ == "left") { - const VType*base_type = base_->peek_type(); + const VTypeArray*arr = dynamic_cast(type); - if(!base_type) { - const ExpName*name = NULL; + if (arr == 0) { + cerr << endl << get_fileline() << ": error: " + << "Cannot apply the '" << name_ << " attribute to non-array objects" + << endl; + ivl_assert(*this, false); + return false; + } - if(scope && (name = dynamic_cast(base_))) { - const perm_string& n = name->peek_name(); - if(const Variable*var = scope->find_variable(n)) - base_type = var->peek_type(); - else if(const Signal*sig = scope->find_signal(n)) - base_type = sig->peek_type(); - else if(const InterfacePort*port = scope->find_param(n)) - base_type = port->type; - } - } + if (arr->dimensions() > 1) { + cerr << endl << get_fileline() << ": error: " + << "Cannot apply the '" << name_ + << " attribute to multidimensional arrays" << endl; + return false; + } - if(!base_type) - return false; // I tried really hard, sorry + if (arr->dimension(0).is_box()) + return false; - const VTypeArray*arr = dynamic_cast(base_type); - if (arr == 0) { - cerr << endl << get_fileline() << ": error: " - << "Cannot apply the '" << name_ << " attribute to non-array objects" - << endl; - ivl_assert(*this, false); - return false; - } + return true; +} - if(name_ == "length") { - int64_t size = arr->get_width(scope); +bool ExpAttribute::evaluate_type_attr(const VType*type, Entity*ent, ScopeBase*scope, int64_t&val) const +{ + if (name_ == "length" && test_array_type(type)) { + int64_t size = type->get_width(scope); - if(size > 0) - val = size; - else - return false; - } else if(name_ == "left") { - arr->dimension(0).msb()->evaluate(scope, val); - } else if(name_ == "right") { - arr->dimension(0).lsb()->evaluate(scope, val); - } else ivl_assert(*this, false); - - return true; + if(size > 0) { + val = size; + return true; + } + } else if (name_ == "left" && test_array_type(type)) { + const VTypeArray*arr = dynamic_cast(type); + return arr->dimension(0).msb()->evaluate(ent, scope, val); + } else if (name_ == "right" && test_array_type(type)) { + const VTypeArray*arr = dynamic_cast(type); + return arr->dimension(0).lsb()->evaluate(ent, scope, val); } return false; } -bool ExpAttribute::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const +bool ExpObjAttribute::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const { - if (!ent || !scope) { // it's impossible to evaluate, probably it is inside a subprogram - return false; - } + const VType*base_type = base_->peek_type(); - if (name_ == "left" || name_ == "right") { - const VType*base_type = base_->peek_type(); - if (base_type == 0) - base_type = base_->probe_type(ent, scope); + if (base_type == NULL) + base_type = base_->probe_type(ent, scope); - ivl_assert(*this, base_type); + if (base_type) + return evaluate_type_attr(base_type, ent, scope, val); - const VTypeArray*arr = dynamic_cast(base_type); - if (arr == 0) { - cerr << endl << get_fileline() << ": error: " - << "Cannot apply the '" << name_ - << " attribute to non-array objects" << endl; - ivl_assert(*this, false); - return false; - } - - ivl_assert(*this, arr->dimensions() == 1); - if(name_ == "left") - arr->dimension(0).msb()->evaluate(ent, scope, val); - else // "right" - arr->dimension(0).lsb()->evaluate(ent, scope, val); - - return true; - } - - return evaluate(scope, val); -} - -/* - * I don't yet know how to evaluate concatenations. It is not likely - * to come up anyhow. - */ -bool ExpConcat::evaluate(ScopeBase*, int64_t&) const -{ return false; } -bool ExpName::evaluate(ScopeBase*scope, int64_t&val) const +bool ExpTypeAttribute::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const { - const VType*type; - Expression*exp; - - if (prefix_.get()) { - cerr << get_fileline() << ": sorry: I don't know how to evaluate ExpName prefix parts." << endl; - return false; - } - - if (!scope) - return false; - - if (!scope->find_constant(name_, type, exp)) - return false; - - return exp->evaluate(scope, val); + return evaluate_type_attr(base_, ent, scope, val); } bool ExpName::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const { if (prefix_.get()) { - cerr << get_fileline() << ": sorry: I don't know how to evaluate ExpName prefix parts." << endl; - return false; + cerr << get_fileline() << ": sorry: I don't know how to evaluate " + << "ExpName prefix parts." << endl; + return false; } - const InterfacePort*gen = ent->find_generic(name_); - if (gen) { - cerr << get_fileline() << ": sorry: I don't necessarily handle generic overrides." << endl; + 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); + // Evaluate the default expression and use that. + if (gen->expr) + return gen->expr->evaluate(ent, scope, val); + } } - return evaluate(scope, val); + if (scope) { + const VType*type; + Expression*exp; + + if (scope->find_constant(name_, type, exp)) + return exp->evaluate(ent, scope, val); + } + + return false; } -bool ExpShift::evaluate(ScopeBase*scope, int64_t&val) const +bool ExpShift::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const { int64_t val1, val2; bool rc; - rc = eval_operand1(scope, val1); + rc = eval_operand1(ent, scope, val1); if (rc == false) return false; - rc = eval_operand2(scope, val2); + rc = eval_operand2(ent, scope, val2); if (rc == false) return false; @@ -252,7 +201,7 @@ bool ExpShift::evaluate(ScopeBase*scope, int64_t&val) const return true; } -/*bool ExpTime::evaluate(ScopeBase*, int64_t&val) const +/*bool ExpTime::evaluate(Entity*, ScopeBase*, int64_t&val) const { double v = to_fs(); @@ -265,8 +214,4 @@ bool ExpShift::evaluate(ScopeBase*scope, int64_t&val) const val = v; return true; } - -bool ExpTime::evaluate(Entity*, ScopeBase*, int64_t&val) const -{ - return evaluate(NULL, val); }*/ diff --git a/vhdlpp/expression_stream.cc b/vhdlpp/expression_stream.cc index d707fdcff..b62225dd3 100644 --- a/vhdlpp/expression_stream.cc +++ b/vhdlpp/expression_stream.cc @@ -61,13 +61,9 @@ void ExpAggregate::choice_t::write_to_stream(ostream&fd) return; } - if (prange_t*rp = range_expressions()) { - rp->msb()->write_to_stream(fd); - if (rp->is_downto()) - fd << " downto "; - else - fd << " to "; - rp->msb()->write_to_stream(fd); + if (ExpRange*rp = range_expressions()) { + rp->write_to_stream(fd); + return; } fd << "/* ERROR */"; @@ -111,7 +107,13 @@ void ExpArithmetic::write_to_stream(ostream&out) const out << ")"; } -void ExpAttribute::write_to_stream(ostream&fd) const +void ExpObjAttribute::write_to_stream(ostream&fd) const +{ + base_->write_to_stream(fd); + fd << "'" << name_; +} + +void ExpTypeAttribute::write_to_stream(ostream&fd) const { base_->write_to_stream(fd); fd << "'" << name_; @@ -316,3 +318,19 @@ void ExpTime::write_to_stream(ostream&fd) const case S: fd << " s"; break; } } + +void ExpRange::write_to_stream(ostream&fd) const +{ + if(range_expr_) { + range_base_->write_to_stream(fd); + fd << (range_reverse_ ? "'reverse_range" : "'range"); + } else { + left_->write_to_stream(fd); + switch(direction_) { + case DOWNTO: fd << " downto "; break; + case TO: fd << " to "; break; + default: ivl_assert(*this, false); break; + } + right_->write_to_stream(fd); + } +} diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index 03f0ff9df..f10b60404 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -417,3 +417,27 @@ int emit_packages(void) return 0; } + +static int elaborate_library_packages(mappackages) +{ + int errors = 0; + + for (map::iterator cur = packages.begin() + ; cur != packages.end() ; ++cur) { + errors += cur->second->elaborate(); + } + + return errors; +} + +int elaborate_libraries() +{ + int errors = 0; + + for (map::iterator cur = libraries.begin() + ; cur != libraries.end() ; ++cur) { + errors += elaborate_library_packages(cur->second.packages); + } + + return errors; +} diff --git a/vhdlpp/library.h b/vhdlpp/library.h index 68009a39a..7fb95851e 100644 --- a/vhdlpp/library.h +++ b/vhdlpp/library.h @@ -24,6 +24,9 @@ class SubprogramHeader; extern void library_set_work_path(const char*work_path); extern void library_add_directory(const char*directory); +int elaborate_libraries(void); +int emit_packages(void); + extern SubprogramHeader*library_find_subprogram(perm_string name); #endif /* IVL_library_H */ diff --git a/vhdlpp/main.cc b/vhdlpp/main.cc index 199f6e910..d6f3a51d4 100644 --- a/vhdlpp/main.cc +++ b/vhdlpp/main.cc @@ -236,20 +236,27 @@ int main(int argc, char*argv[]) return 3; } + errors = elaborate_libraries(); + if (errors > 0) { + fprintf(stderr, "%d errors elaborating libraries.\n", errors); + parser_cleanup(); + return 4; + } + emit_std_types(cout); errors = emit_packages(); if (errors > 0) { fprintf(stderr, "%d errors emitting packages.\n", errors); parser_cleanup(); - return 4; + return 5; } errors = emit_entities(); if (errors > 0) { fprintf(stderr, "%d errors emitting design.\n", errors); - parser_cleanup(); - return 4; + parser_cleanup(); + return 6; } parser_cleanup(); diff --git a/vhdlpp/package.cc b/vhdlpp/package.cc index 64d20fc80..40730f026 100644 --- a/vhdlpp/package.cc +++ b/vhdlpp/package.cc @@ -41,6 +41,18 @@ void Package::set_library(perm_string lname) from_library_ = lname; } +int Package::elaborate() +{ + int errors = 0; + + for (map::const_iterator cur = cur_subprograms_.begin() + ; cur != cur_subprograms_.end() ; ++cur) { + errors += cur->second->elaborate(); + } + + return errors; +} + /* * The Package::write_to_stream is used to write the package to the * work space (or library) so writes proper VHDL that the library diff --git a/vhdlpp/package.h b/vhdlpp/package.h index fb6bfb8ac..3f75c8820 100644 --- a/vhdlpp/package.h +++ b/vhdlpp/package.h @@ -42,6 +42,7 @@ class Package : public Scope, public LineInfo { void write_to_stream(std::ostream&fd) const; int emit_package(std::ostream&fd) const; + int elaborate(); private: perm_string from_library_; diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 0c6884253..dbc561867 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -87,10 +87,6 @@ static ActiveScope*active_scope = new ActiveScope; static stack scope_stack; static SubprogramHeader*active_sub = NULL; -// perm_strings for attributes -const static perm_string left_attr = perm_string::literal("left"); -const static perm_string right_attr = perm_string::literal("right"); - /* * When a scope boundary starts, call the push_scope function to push * a scope context. Preload this scope context with the contents of @@ -245,8 +241,9 @@ static void touchup_interface_for_functions(std::list*ports) const VType* vtype; - prange_t* range; - std::list*range_list; + ExpRange*range; + std::list*range_list; + ExpRange::range_dir_t range_dir; ExpArithmetic::fun_t arithmetic_op; std::list*adding_terms; @@ -305,8 +302,6 @@ static void touchup_interface_for_functions(std::list*ports) /* The rules may have types. */ -%type direction - %type adding_operator %type simple_expression_terms @@ -341,7 +336,7 @@ static void touchup_interface_for_functions(std::list*ports) %type variable_declaration_assign_opt waveform_element interface_element_expression %type waveform waveform_elements -%type name_list expression_list +%type name_list expression_list argument_list argument_list_opt %type process_sensitivity_list process_sensitivity_list_opt %type selected_names use_clause @@ -372,6 +367,7 @@ static void touchup_interface_for_functions(std::list*ports) %type range %type range_list index_constraint +%type direction %type case_statement_alternative %type case_statement_alternative_list @@ -448,11 +444,18 @@ architecture_statement_part } ; +argument_list : '(' expression_list ')' { $$ = $2; }; + +argument_list_opt + : argument_list { $$ = $1; } + | { $$ = 0; } + ; + assertion_statement : K_assert expression report_statement { ReportStmt*report = dynamic_cast($3); assert(report); - AssertStmt*tmp = new AssertStmt($2, report->message().c_str(), report->severity()); + AssertStmt*tmp = new AssertStmt($2, report->message(), report->severity()); delete report; FILE_NAME(tmp,@2); $$ = tmp; @@ -752,8 +755,9 @@ composite_type_definition /* unbounded_array_definition IEEE 1076-2008 P5.3.2.1 */ | K_array '(' index_subtype_definition_list ')' K_of subtype_indication - { std::list r; - r.push_back(new prange_t(NULL, NULL, true)); // NULL boundaries indicate unbounded array type + { 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; } @@ -983,8 +987,10 @@ design_units | design_unit ; - /* Indicate the direction as a flag, with "downto" being TRUE. */ -direction : K_to { $$ = false; } | K_downto { $$ = true; } ; +direction + : K_to { $$ = ExpRange::TO; } + | K_downto { $$ = ExpRange::DOWNTO; } + ; element_association : choices ARROW expression @@ -1258,8 +1264,8 @@ file_declaration // add file_open() call in 'initial' block params.push_back(new ExpName(*cur)); - params.push_back($5->filename()); - params.push_back($5->kind()); + 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); @@ -1268,6 +1274,8 @@ file_declaration params.push_back(new ExpName(*cur)); ProcedureCall*fclose_call = new ProcedureCall(perm_string::literal("file_close"), ¶ms); active_scope->add_finalizer(fclose_call); + + delete $5; } } @@ -1498,7 +1506,7 @@ index_constraint | '(' error ')' { errormsg(@2, "Errors in the index constraint.\n"); yyerrok; - $$ = new list; + $$ = new list; } ; @@ -1679,14 +1687,14 @@ name /* IEEE 1076-2008 P8.1 */ 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 '(' expression_list ')' + | 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, $3); + ExpName*tmp = new ExpName(name, $2); $$ = tmp; } else { - ExpFunc*tmp = new ExpFunc(name, $3); + ExpFunc*tmp = new ExpFunc(name, $2); $$ = tmp; } FILE_NAME($$, @1); @@ -1876,10 +1884,18 @@ prefix /* IEEE 1076-2008 P8.1 */ primary : name { $$ = $1; } - | name '\'' IDENTIFIER - { perm_string name = lex_strings.make($3); - ExpName*base = dynamic_cast ($1); - ExpAttribute*tmp = new ExpAttribute(base, name); + | name '\'' IDENTIFIER argument_list_opt + { ExpAttribute*tmp = NULL; + perm_string attr = lex_strings.make($3); + ExpName*base = dynamic_cast($1); + const VType*type = parse_type_by_name(base->peek_name()); + + if(type) { + tmp = new ExpTypeAttribute(type, attr, $4); + } else { + tmp = new ExpObjAttribute(base, attr, $4); + } + FILE_NAME(tmp, @3); delete[]$3; $$ = tmp; @@ -1980,11 +1996,11 @@ procedure_call delete[] $1; $$ = tmp; } - | IDENTIFIER '(' expression_list ')' ';' + | IDENTIFIER argument_list ';' { - ProcedureCall* tmp = new ProcedureCall(lex_strings.make($1), $3); + ProcedureCall* tmp = new ProcedureCall(lex_strings.make($1), $2); delete[] $1; - delete $3; // parameters are copied in this variant + delete $2; // parameters are copied in this variant $$ = tmp; } | IDENTIFIER '(' error ')' ';' @@ -2096,18 +2112,15 @@ process_sensitivity_list range : simple_expression direction simple_expression - { prange_t* tmp = new prange_t($1, $3, $2); + { ExpRange* tmp = new ExpRange($1, $3, $2); $$ = tmp; } | name '\'' K_range { - prange_t*tmp = NULL; + ExpRange*tmp = NULL; ExpName*name = NULL; if((name = dynamic_cast($1))) { - ExpAttribute*left = new ExpAttribute(name, left_attr); - ExpAttribute*right = new ExpAttribute(name, right_attr); - tmp = new prange_t(left, right, true); - tmp->set_auto_dir(); + tmp = new ExpRange(name, false); } else { errormsg(@1, "'range attribute can be used with named expressions only"); } @@ -2115,13 +2128,10 @@ range } | name '\'' K_reverse_range { - prange_t*tmp = NULL; + ExpRange*tmp = NULL; ExpName*name = NULL; if((name = dynamic_cast($1))) { - ExpAttribute*left = new ExpAttribute(name, left_attr); - ExpAttribute*right = new ExpAttribute(name, right_attr); - tmp = new prange_t(left, right, false); - tmp->set_auto_dir(); + tmp = new ExpRange(name, true); } else { errormsg(@1, "'reverse_range attribute can be used with named expressions only"); } @@ -2131,12 +2141,12 @@ range range_list : range - { list*tmp = new list; + { list*tmp = new list; tmp->push_back($1); $$ = tmp; } | range_list ',' range - { list*tmp = $1; + { list*tmp = $1; tmp->push_back($3); $$ = tmp; } @@ -2185,10 +2195,9 @@ relation ; report_statement - : K_report STRING_LITERAL severity_opt ';' + : K_report expression severity_opt ';' { ReportStmt*tmp = new ReportStmt($2, $3); FILE_NAME(tmp,@2); - delete[]$2; $$ = tmp; } diff --git a/vhdlpp/parse_misc.cc b/vhdlpp/parse_misc.cc index 752f7eeb9..cc9de0a1e 100644 --- a/vhdlpp/parse_misc.cc +++ b/vhdlpp/parse_misc.cc @@ -113,14 +113,14 @@ static const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_n } const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name, - ScopeBase*scope, list*ranges) + ScopeBase*scope, list*ranges) { if (ranges->size() == 1) { - prange_t*tmpr = ranges->front(); - Expression*lef = tmpr->expr_left(); - Expression*rig = tmpr->expr_right(); + ExpRange*tmpr = ranges->front(); + Expression*lef = tmpr->left(); + Expression*rig = tmpr->right(); return calculate_subtype_array(loc, base_name, scope, - lef, tmpr->is_downto(), rig); + lef, tmpr->direction(), rig); } sorrymsg(loc, "Don't know how to handle multiple ranges here.\n"); @@ -130,7 +130,7 @@ const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name, const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name, ScopeBase*scope, Expression*range_left, - bool downto, + int direction, Expression*range_right) { const VType*base_type = parse_type_by_name(lex_strings.make(base_name)); @@ -148,7 +148,7 @@ const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name, if(range_left->evaluate(scope, left_val) && range_right->evaluate(scope, right_val)) { subtype = new VTypeRangeConst(base_type, left_val, right_val); } else { - subtype = new VTypeRangeExpr(base_type, range_left, range_right, downto); + subtype = new VTypeRangeExpr(base_type, range_left, range_right, direction); } return subtype; diff --git a/vhdlpp/parse_misc.h b/vhdlpp/parse_misc.h index a18335245..195264298 100644 --- a/vhdlpp/parse_misc.h +++ b/vhdlpp/parse_misc.h @@ -26,7 +26,7 @@ class ActiveScope; class Architecture; class Expression; class Package; -class prange_t; +class ExpRange; class ScopeBase; class VType; @@ -35,11 +35,11 @@ extern void bind_architecture_to_entity(const char*ename, Architecture*arch); extern const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name, ScopeBase*scope, - std::list*ranges); + std::list*ranges); extern const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name, ScopeBase*scope, Expression*range_left, - bool downto, + int direction, Expression*range_right); /* diff --git a/vhdlpp/parse_types.h b/vhdlpp/parse_types.h index 403057831..711d45a0b 100644 --- a/vhdlpp/parse_types.h +++ b/vhdlpp/parse_types.h @@ -26,7 +26,8 @@ class named_expr_t { public: - named_expr_t (perm_string n, Expression*e) : name_(n), expr_(e) { } + named_expr_t(perm_string n, Expression*e) : name_(n), expr_(e) { } + ~named_expr_t() { delete expr_; } perm_string name() const { return name_; } Expression* expr() const { return expr_; } @@ -68,35 +69,6 @@ class instant_list_t { std::list* labels_; }; -class prange_t { - public: - prange_t(Expression* left, Expression* right, bool dir) - : left_(left), right_(right), direction_(dir), auto_dir_(false) {} - prange_t(const prange_t&other) : - left_(other.left_->clone()), right_(other.right_->clone()), - direction_(other.direction_), auto_dir_(other.auto_dir_) {} - ~prange_t() { delete left_; delete right_; } - void dump(ostream&out, int indent) const; - - inline Expression*msb() { return direction_? left_ : right_; } - inline Expression*lsb() { return direction_? right_: left_; } - - inline bool is_downto() const { return direction_; } - inline void set_auto_dir(bool enabled = true) { auto_dir_ = enabled; }; - inline bool is_auto_dir() const { return auto_dir_; } - - inline Expression*expr_left() { return left_; } - inline Expression*expr_right() { return right_; } - - private: - Expression *left_, *right_; - bool direction_; - bool auto_dir_; - - private: //not implemented - prange_t operator=(const prange_t&); -}; - struct adding_term { ExpArithmetic::fun_t op; Expression*term; diff --git a/vhdlpp/scope.cc b/vhdlpp/scope.cc index bc1e42979..5084986a3 100644 --- a/vhdlpp/scope.cc +++ b/vhdlpp/scope.cc @@ -90,6 +90,7 @@ void ScopeBase::cleanup() * objects from the other scopes untouched. */ delete_all(new_signals_); + delete_all(new_variables_); delete_all(new_components_); delete_all(cur_types_); delete_all(cur_constants_); diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index 444583d09..df1f1daba 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -90,6 +90,8 @@ class ScopeBase { finalizers_.push_back(s); } + void dump_scope(ostream&out) const; + protected: void cleanup(); @@ -154,9 +156,6 @@ class Scope : public ScopeBase { ComponentBase* find_component(perm_string by_name); - public: - void dump_scope(ostream&out) const; - protected: // Helper method for emitting signals in the scope. int emit_signals(ostream&out, Entity*ent, Architecture*arc); diff --git a/vhdlpp/sequential.cc b/vhdlpp/sequential.cc index 042850426..3e572fce0 100644 --- a/vhdlpp/sequential.cc +++ b/vhdlpp/sequential.cc @@ -185,7 +185,7 @@ ProcedureCall::ProcedureCall(perm_string name, std::list* param_lis for(std::list::const_iterator it = param_list->begin(); it != param_list->end(); ++it) { - param_list_->push_back(new named_expr_t(empty_perm_string, (*it)->clone())); + param_list_->push_back(new named_expr_t(empty_perm_string, *it)); } } @@ -199,6 +199,8 @@ ProcedureCall::~ProcedureCall() param_list_->pop_front(); delete cur; } + + delete param_list_; } ReturnStmt::ReturnStmt(Expression*val) @@ -238,7 +240,7 @@ void LoopStatement::visit(SeqStmtVisitor& func) func(this); } -ForLoopStatement::ForLoopStatement(perm_string scope_name, perm_string it, prange_t* range, list* stmts) +ForLoopStatement::ForLoopStatement(perm_string scope_name, perm_string it, ExpRange* range, list* stmts) : LoopStatement(scope_name, stmts), it_(it), range_(range) { } @@ -278,26 +280,24 @@ BasicLoopStatement::~BasicLoopStatement() { } -ReportStmt::ReportStmt(const char*msg, severity_t sev) +ReportStmt::ReportStmt(Expression*msg, severity_t sev) : msg_(msg), severity_(sev) { if(sev == ReportStmt::UNSPECIFIED) severity_ = ReportStmt::NOTE; } -AssertStmt::AssertStmt(Expression*condition, const char*msg, ReportStmt::severity_t sev) -: ReportStmt("", sev), cond_(condition) +AssertStmt::AssertStmt(Expression*condition, Expression*msg, ReportStmt::severity_t sev) +: ReportStmt(msg, sev), cond_(condition) { if(msg == NULL) - msg_ = default_msg_; - else - msg_ = std::string(msg); + msg_ = new ExpString(default_msg_); if(sev == ReportStmt::UNSPECIFIED) severity_ = ReportStmt::ERROR; } -const std::string AssertStmt::default_msg_ = std::string("Assertion violation."); +const char*AssertStmt::default_msg_ = "Assertion violation."; WaitForStmt::WaitForStmt(Expression*delay) : delay_(delay) diff --git a/vhdlpp/sequential.h b/vhdlpp/sequential.h index a952981c0..ce68bcc3e 100644 --- a/vhdlpp/sequential.h +++ b/vhdlpp/sequential.h @@ -250,7 +250,7 @@ class WhileLoopStatement : public LoopStatement { class ForLoopStatement : public LoopStatement { public: ForLoopStatement(perm_string loop_name, - perm_string index, prange_t*, list*); + perm_string index, ExpRange*, list*); ~ForLoopStatement(); int elaborate(Entity*ent, ScopeBase*scope); @@ -264,7 +264,7 @@ class ForLoopStatement : public LoopStatement { int emit_runtime_(ostream&out, Entity*ent, ScopeBase*scope); perm_string it_; - prange_t* range_; + ExpRange* range_; }; class BasicLoopStatement : public LoopStatement { @@ -280,24 +280,27 @@ class ReportStmt : public SequentialStmt { public: typedef enum { UNSPECIFIED, NOTE, WARNING, ERROR, FAILURE } severity_t; - ReportStmt(const char*message, severity_t severity = NOTE); + ReportStmt(Expression*message, severity_t severity); virtual ~ReportStmt() {} void dump(ostream&out, int indent) const; + int elaborate(Entity*ent, ScopeBase*scope); int emit(ostream&out, Entity*entity, ScopeBase*scope); void write_to_stream(std::ostream&fd); - inline const std::string& message() const { return msg_; } + inline Expression*message() const { return msg_; } inline severity_t severity() const { return severity_; } protected: - std::string msg_; + void dump_sev_msg(ostream&out, int indent) const; + + Expression*msg_; severity_t severity_; }; class AssertStmt : public ReportStmt { public: - AssertStmt(Expression*condition, const char*message, + AssertStmt(Expression*condition, Expression*message, ReportStmt::severity_t severity = ReportStmt::ERROR); void dump(ostream&out, int indent) const; @@ -309,7 +312,7 @@ class AssertStmt : public ReportStmt { Expression*cond_; // Message displayed when there is no report assigned. - static const std::string default_msg_; + static const char*default_msg_; }; class WaitForStmt : public SequentialStmt { diff --git a/vhdlpp/sequential_debug.cc b/vhdlpp/sequential_debug.cc index 149021440..7abb63d6f 100644 --- a/vhdlpp/sequential_debug.cc +++ b/vhdlpp/sequential_debug.cc @@ -169,16 +169,24 @@ void BasicLoopStatement::dump(ostream&out, int indent) const void ReportStmt::dump(ostream&out, int indent) const { out << setw(indent) << "" << "ReportStmt at file=" << get_fileline() << endl; - out << setw(indent+3) << "" << "severity: " << severity_ << endl; - out << setw(indent+3) << "" << "message: " << msg_ << endl; + dump_sev_msg(out, indent+3); +} + +void ReportStmt::dump_sev_msg(ostream&out, int indent) const +{ + out << setw(indent) << "" << "severity: " << severity_ << endl; + + if(msg_) { + out << setw(indent) << "" << "message: "; + msg_->dump(out, indent); + } } void AssertStmt::dump(ostream&out, int indent) const { out << setw(indent) << "" << "AssertStmt at file=" << get_fileline() << endl; out << setw(indent+3) << "" << "condition: "; - cond_->dump(out, indent+3); - ReportStmt::dump(out, indent+3); + dump_sev_msg(out, indent+3); } void WaitForStmt::dump(ostream&out, int indent) const diff --git a/vhdlpp/sequential_elaborate.cc b/vhdlpp/sequential_elaborate.cc index 4b033c6e5..98b8766c0 100644 --- a/vhdlpp/sequential_elaborate.cc +++ b/vhdlpp/sequential_elaborate.cc @@ -217,9 +217,17 @@ int BasicLoopStatement::elaborate(Entity*, ScopeBase*) return 0; } +int ReportStmt::elaborate(Entity*ent, ScopeBase*scope) +{ + return msg_->elaborate_expr(ent, scope, &primitive_STRING); +} + int AssertStmt::elaborate(Entity*ent, ScopeBase*scope) { - return cond_->elaborate_expr(ent, scope, cond_->probe_type(ent, scope)); + int errors = 0; + errors += ReportStmt::elaborate(ent, scope); + errors += cond_->elaborate_expr(ent, scope, cond_->probe_type(ent, scope)); + return errors; } int WaitForStmt::elaborate(Entity*ent, ScopeBase*scope) diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index 9e122b213..0431a1f53 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -383,10 +383,10 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, ScopeBase*scope) ivl_assert(*this, range_); int64_t start_val; - bool start_rc = range_->msb()->evaluate(ent, scope, start_val); + bool start_rc = range_->left()->evaluate(ent, scope, start_val); int64_t finish_val; - bool finish_rc = range_->lsb()->evaluate(ent, scope, finish_val); + bool finish_rc = range_->right()->evaluate(ent, scope, finish_val); perm_string scope_name = loop_name(); if (scope_name.nil()) { @@ -403,48 +403,31 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, ScopeBase*scope) // determined during the run-time errors += emit_runtime_(out, ent, scope); } else { - bool dir = range_->is_downto(); + ExpRange::range_dir_t dir = range_->direction(); - if (!dir) { - int64_t tmp = start_val; - start_val = finish_val; - finish_val = tmp; - } + if(dir == ExpRange::AUTO) + dir = start_val < finish_val ? ExpRange::TO : ExpRange::DOWNTO; - if (dir && (start_val < finish_val)) { - if(range_->is_auto_dir()) { - dir = false; - } else { - out << "begin /* Degenerate loop at " << get_fileline() - << ": " << start_val - << " downto " << finish_val << " */ end" << endl - << "end" << endl; - return errors; - } - } - - else if (!dir && start_val > finish_val) { - if(range_->is_auto_dir()) { - dir = true; - } else { - out << "begin /* Degenerate loop at " << get_fileline() - << ": " << start_val - << " to " << finish_val << " */ end" << endl - << "end" << endl; - return errors; - } + if ((dir == ExpRange::DOWNTO && start_val < finish_val) || + (dir == ExpRange::TO && start_val > finish_val)) { + out << "begin /* Degenerate loop at " << get_fileline() + << ": " << start_val; + out << (dir == ExpRange::DOWNTO ? " downto " : " to "); + out << finish_val << " */ end" << endl + << "end" << endl; + return errors; } out << "for (\\" << it_ << " = " << start_val << " ; "; - if (dir) + if (dir == ExpRange::DOWNTO) out << "\\" << it_ << " >= " << finish_val; else out << "\\" << it_ << " <= " << finish_val; out << "; \\" << it_ << " = \\" << it_; - if (dir) + if (dir == ExpRange::DOWNTO) out << " - 1)"; else out << " + 1)"; @@ -463,9 +446,7 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, ScopeBase*scope) void ForLoopStatement::write_to_stream(ostream&fd) { fd << "for " << it_ << " in "; - range_->expr_left()->write_to_stream(fd); - fd << " to "; - range_->expr_right()->write_to_stream(fd); + range_->write_to_stream(fd); fd << " loop" << endl; write_to_stream_substatements(fd); fd << "end loop;" << endl; @@ -476,41 +457,43 @@ int ForLoopStatement::emit_runtime_(ostream&out, Entity*ent, ScopeBase*scope) int errors = 0; out << "for (\\" << it_ << " = "; - errors += range_->expr_left()->emit(out, ent, scope); + errors += range_->left()->emit(out, ent, scope); // Twisted way of determining the loop direction at runtime out << " ;\n("; - errors += range_->expr_left()->emit(out, ent, scope); + errors += range_->left()->emit(out, ent, scope); out << " < "; - errors += range_->expr_right()->emit(out, ent, scope); + errors += range_->right()->emit(out, ent, scope); out << " ? \\" << it_ << " <= "; - errors += range_->expr_right()->emit(out, ent, scope); + errors += range_->right()->emit(out, ent, scope); out << " : \\" << it_ << " >= "; - errors += range_->expr_right()->emit(out, ent, scope); + errors += range_->right()->emit(out, ent, scope); out << ");\n\\" << it_ << " = \\" << it_ << " + ("; - errors += range_->expr_left()->emit(out, ent, scope); + errors += range_->left()->emit(out, ent, scope); out << " < "; - errors += range_->expr_right()->emit(out, ent, scope); + errors += range_->right()->emit(out, ent, scope); out << " ? 1 : -1))"; return errors; } -int ReportStmt::emit(ostream&out, Entity*, ScopeBase*) +int ReportStmt::emit(ostream&out, Entity*ent, ScopeBase*scope) { - out << "$display(\""; + out << "$display(\"** "; switch(severity_) { - case NOTE: out << "** Note: "; break; - case WARNING: out << "** Warning: "; break; - case ERROR: out << "** Error: "; break; - case FAILURE: out << "** Failure: "; break; + case NOTE: out << "Note"; break; + case WARNING: out << "Warning"; break; + case ERROR: out << "Error"; break; + case FAILURE: out << "Failure"; break; case UNSPECIFIED: ivl_assert(*this, false); break; } - out << ExpString::escape_quot(msg_); - out << " (" << get_fileline() << ")\");"; + out << ": \","; + + msg_->emit(out, ent, scope); + out << ",\" (" << get_fileline() << ")\");"; if(severity_ == FAILURE) out << "$finish();"; @@ -522,7 +505,8 @@ int ReportStmt::emit(ostream&out, Entity*, ScopeBase*) void ReportStmt::write_to_stream(std::ostream&fd) { - fd << "report \"" << ExpString::escape_quot(msg_) << "\"" << std::endl; + fd << "report "; + msg_->write_to_stream(fd); fd << "severity "; switch(severity_) @@ -563,7 +547,7 @@ int WaitForStmt::emit(ostream&out, Entity*ent, ScopeBase*scope) out << "#("; errors += delay_->emit(out, ent, scope); - out << ")"; + out << ");" << std::endl; return errors; } @@ -586,6 +570,7 @@ int WaitStmt::emit(ostream&out, Entity*ent, ScopeBase*scope) case UNTIL: if(!sens_list_.empty()) { out << "@("; + for(std::set::iterator it = sens_list_.begin(); it != sens_list_.end(); ++it) { if(it != sens_list_.begin()) @@ -594,7 +579,7 @@ int WaitStmt::emit(ostream&out, Entity*ent, ScopeBase*scope) (*it)->emit(out, ent, scope); } - out << ");"; + out << "); "; } out << "wait("; diff --git a/vhdlpp/std_types.cc b/vhdlpp/std_types.cc index 516b6ac17..9bb9744dd 100644 --- a/vhdlpp/std_types.cc +++ b/vhdlpp/std_types.cc @@ -46,20 +46,20 @@ const VTypeArray primitive_UNSIGNED(&primitive_STDLOGIC, vector*enum_BOOLEAN_vals = new list; - enum_BOOLEAN_vals->push_back(perm_string::literal("false")); - enum_BOOLEAN_vals->push_back(perm_string::literal("true")); - VTypeEnum*enum_BOOLEAN = new VTypeEnum(enum_BOOLEAN_vals); + list enum_BOOLEAN_vals; + enum_BOOLEAN_vals.push_back(perm_string::literal("false")); + enum_BOOLEAN_vals.push_back(perm_string::literal("true")); + VTypeEnum*enum_BOOLEAN = new VTypeEnum(&enum_BOOLEAN_vals); type_BOOLEAN.set_definition(enum_BOOLEAN); std_types[type_BOOLEAN.peek_name()] = &type_BOOLEAN; std_enums.push_back(enum_BOOLEAN); // file_open_kind - list*enum_FILE_OPEN_KIND_vals = new list; - enum_FILE_OPEN_KIND_vals->push_back(perm_string::literal("read_mode")); - enum_FILE_OPEN_KIND_vals->push_back(perm_string::literal("write_mode")); - enum_FILE_OPEN_KIND_vals->push_back(perm_string::literal("append_mode")); - VTypeEnum*enum_FILE_OPEN_KIND = new VTypeEnum(enum_FILE_OPEN_KIND_vals); + list enum_FILE_OPEN_KIND_vals; + enum_FILE_OPEN_KIND_vals.push_back(perm_string::literal("read_mode")); + enum_FILE_OPEN_KIND_vals.push_back(perm_string::literal("write_mode")); + enum_FILE_OPEN_KIND_vals.push_back(perm_string::literal("append_mode")); + VTypeEnum*enum_FILE_OPEN_KIND = new VTypeEnum(&enum_FILE_OPEN_KIND_vals); type_FILE_OPEN_KIND.set_definition(enum_FILE_OPEN_KIND); std_types[type_FILE_OPEN_KIND.peek_name()] = &type_FILE_OPEN_KIND; std_enums.push_back(enum_FILE_OPEN_KIND); @@ -80,10 +80,12 @@ void delete_global_types() { typedef_context_t typedef_ctx; for(map::iterator cur = std_types.begin(); - cur != std_types.end() ; ++ cur) { + cur != std_types.end(); ++cur) { delete cur->second->peek_definition(); delete cur->second; } + + // std_enums are destroyed above } const VTypeEnum*find_std_enum_name(perm_string name) diff --git a/vhdlpp/std_types.h b/vhdlpp/std_types.h index 033ac2167..b00dd503f 100644 --- a/vhdlpp/std_types.h +++ b/vhdlpp/std_types.h @@ -23,7 +23,6 @@ class ActiveScope; void emit_std_types(ostream&out); -int emit_packages(void); void generate_global_types(ActiveScope*res); bool is_global_type(perm_string type_name); void delete_global_types(); diff --git a/vhdlpp/subprogram.cc b/vhdlpp/subprogram.cc index 59862f97d..80839b557 100644 --- a/vhdlpp/subprogram.cc +++ b/vhdlpp/subprogram.cc @@ -53,6 +53,18 @@ void SubprogramBody::set_statements(list*stmt) statements_ = stmt; } +int SubprogramBody::elaborate() +{ + int errors = 0; + + for (list::const_iterator cur = statements_->begin() + ; cur != statements_->end() ; ++cur) { + errors += (*cur)->elaborate(0, this); + } + + return errors; +} + void SubprogramBody::write_to_stream(ostream&fd) const { for (map::const_iterator cur = new_variables_.begin() diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h index 6972ae0be..a07570fac 100644 --- a/vhdlpp/subprogram.h +++ b/vhdlpp/subprogram.h @@ -45,6 +45,7 @@ class SubprogramBody : public LineInfo, public ScopeBase { void set_statements(std::list*statements); inline bool empty_statements() const { return !statements_ || statements_->empty(); } + int elaborate(); int emit(ostream&out, Entity*ent, ScopeBase*scope); // Emit body as it would show up in a package. @@ -89,6 +90,8 @@ class SubprogramHeader : public LineInfo { inline perm_string name() const { return name_; } + int elaborate() { return (body_ ? body_->elaborate() : 0); } + // 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 diff --git a/vhdlpp/vsignal.cc b/vhdlpp/vsignal.cc index 38516dbaf..68cec4c4a 100644 --- a/vhdlpp/vsignal.cc +++ b/vhdlpp/vsignal.cc @@ -72,8 +72,7 @@ int Variable::emit(ostream&out, Entity*ent, ScopeBase*scope) VType::decl_t decl; type_elaborate_(decl); - if (peek_refcnt_sequ_() > 0 || !peek_type()->can_be_packed()) - decl.reg_flag = true; + decl.reg_flag = true; errors += decl.emit(out, peek_name()); Expression*init_expr = peek_init_expr(); diff --git a/vhdlpp/vtype.cc b/vhdlpp/vtype.cc index 6bf8c4eb2..64e94ef46 100644 --- a/vhdlpp/vtype.cc +++ b/vhdlpp/vtype.cc @@ -108,21 +108,18 @@ VTypeArray::VTypeArray(const VType*element, const vector&r, /* * Create a VTypeArray range set from a list of parsed ranges. - * FIXME: We are copying pointers from the prange_t object into the - * range_t. This means that we cannot delete the prange_t object + * FIXME: We are copying pointers from the ExpRange object into the + * range_t. This means that we cannot delete the ExpRange object * unless we invent a way to remove the pointers from that object. So * this is a memory leak. Something to fix. */ -VTypeArray::VTypeArray(const VType*element, std::list*r, bool sv) +VTypeArray::VTypeArray(const VType*element, std::list*r, bool sv) : etype_(element), ranges_(r->size()), signed_flag_(sv), parent_(NULL) { for (size_t idx = 0 ; idx < ranges_.size() ; idx += 1) { - prange_t*curp = r->front(); + ExpRange*curp = r->front(); r->pop_front(); - Expression*msb = curp->msb(); - Expression*lsb = curp->lsb(); - bool dir = curp->is_downto(); - ranges_[idx] = range_t(msb, lsb, dir); + ranges_[idx] = range_t(curp->msb(), curp->lsb(), curp->direction()); } } diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index d97d13a9a..cc310ad90 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -33,7 +33,7 @@ class Architecture; class ScopeBase; class Entity; class Expression; -class prange_t; +class ExpRange; class VTypeDef; class ScopeBase; @@ -210,7 +210,7 @@ class VTypeArray : public VType { public: VTypeArray(const VType*etype, const std::vector&r, bool signed_vector = false); - VTypeArray(const VType*etype, std::list*r, bool signed_vector = false); + VTypeArray(const VType*etype, std::list*r, bool signed_vector = false); VTypeArray(const VType*etype, int msb, int lsb, bool signed_vector = false); ~VTypeArray(); diff --git a/vpi/sys_display.c b/vpi/sys_display.c index a7a34dfa7..28031a73f 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -169,10 +169,11 @@ static int get_default_format(const char *name) int default_format; switch(name[ strlen(name)-1 ]){ - /* writE/strobE or monitoR or displaY/fdisplaY or sformaT */ + /* writE/strobE or monitoR or displaY/fdisplaY or sformaT/sformatF */ case 'e': case 'r': case 't': + case 'f': case 'y': default_format = vpiDecStrVal; break; case 'h': default_format = vpiHexStrVal; break; case 'o': default_format = vpiOctStrVal; break; @@ -620,10 +621,6 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, case 't': case 'T': *idx += 1; - if (plus != 0) { - vpi_printf("WARNING: %s:%d: invalid format %s%s.\n", - info->filename, info->lineno, info->name, fmtb); - } if (*idx >= info->nitems) { vpi_printf("WARNING: %s:%d: missing argument for %s%s.\n", info->filename, info->lineno, info->name, fmtb); @@ -647,6 +644,29 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, } else { char *tbuf; PLI_INT32 time_units = vpi_get(vpiTimeUnit, info->scope); + + if (plus != 0) { + /* Icarus-specific extension to print out time units. + * It is needed by vhdlpp to correctly implement time'image(). */ + PLI_INT32 time_prec = vpi_get(vpiTimePrecision, info->scope); + + if(time_units < -12) + timeformat_info.suff = strdup(" fs"); + else if(time_units < -9) + timeformat_info.suff = strdup(" ps"); + else if(time_units < -6) + timeformat_info.suff = strdup(" ns"); + else if(time_units < -3) + timeformat_info.suff = strdup(" us"); + else if(time_units < 0) + timeformat_info.suff = strdup(" ms"); + else + timeformat_info.suff = strdup(" s"); + + /* Adjust shift for get_time(), so the number indeed matches the unit */ + time_units += (3 + (time_units % 3)) % 3 + (time_prec - time_units); + } + unsigned swidth, free_flag = 0; unsigned suff_len = strlen(timeformat_info.suff); char *cp; @@ -1238,7 +1258,8 @@ static PLI_INT32 sys_display_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) return sys_common_compiletf(name, 0, 0); } -/* This implements the $display/$fdisplay and the $write/$fwrite based tasks. */ +/* This implements the $sformatf, $display/$fdisplay + * and the $write/$fwrite based tasks. */ static PLI_INT32 sys_display_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) { vpiHandle callh, argv, scope; @@ -1246,6 +1267,7 @@ static PLI_INT32 sys_display_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) char* result; unsigned int size; PLI_UINT32 fd_mcd; + s_vpi_value val; callh = vpi_handle(vpiSysTfCall, 0); argv = vpi_iterate(vpiArgument, callh); @@ -1254,7 +1276,6 @@ static PLI_INT32 sys_display_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) if(name[1] == 'f') { errno = 0; vpiHandle arg = vpi_scan(argv); - s_vpi_value val; val.format = vpiIntVal; vpi_get_value(arg, &val); fd_mcd = val.value.integer; @@ -1275,7 +1296,11 @@ static PLI_INT32 sys_display_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) vpi_free_object(argv); return 0; } + } else if(strncmp(name,"$sformatf",9) == 0) { + /* return as a string */ + fd_mcd = 0; } else { + /* stdout */ fd_mcd = 1; } @@ -1293,13 +1318,21 @@ static PLI_INT32 sys_display_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) /* Because %u and %z may put embedded NULL characters into the * returned string strlen() may not match the real size! */ result = get_display(&size, &info); - my_mcd_rawwrite(fd_mcd, result, size); - if ((strncmp(name,"$display",8) == 0) || - (strncmp(name,"$fdisplay",9) == 0)) my_mcd_rawwrite(fd_mcd, "\n", 1); + if(fd_mcd > 0) { + my_mcd_rawwrite(fd_mcd, result, size); + if ((strncmp(name,"$display",8) == 0) || + (strncmp(name,"$fdisplay",9) == 0)) my_mcd_rawwrite(fd_mcd, "\n", 1); + } else { + /* Return as a string ($sformatf) */ + val.format = vpiStringVal; + val.value.str = result; + vpi_put_value(callh, &val, 0, vpiNoDelay); + } + + free(result); free(info.filename); free(info.items); - free(result); return 0; } @@ -1665,7 +1698,7 @@ static PLI_INT32 sys_sformat_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) if (argv == 0) { vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s requires at least two argument.\n", name); + vpi_printf("%s requires at least two arguments.\n", name); vpi_control(vpiFinish, 1); return 0; } @@ -1686,7 +1719,7 @@ static PLI_INT32 sys_sformat_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) if (arg == 0) { vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s requires at least two argument.\n", name); + vpi_printf("%s requires at least two arguments.\n", name); vpi_control(vpiFinish, 1); return 0; } @@ -1754,6 +1787,46 @@ static PLI_INT32 sys_sformat_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) return 0; } +static PLI_INT32 sys_sformatf_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle arg; + PLI_INT32 type; + + /* Check that there are arguments. */ + if (argv == 0) { + vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s requires at least one argument.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + + /* The first argument must be a string, a register or a SV string. */ + arg = vpi_scan(argv); + if (arg == 0) { + vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s requires at least one argument.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + type = vpi_get(vpiType, arg); + if (((type != vpiConstant && type != vpiParameter) || + vpi_get(vpiConstType, arg) != vpiStringConst) && + type != vpiReg && type != vpiStringVar) { + vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s's first argument must be a string or a register.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + + if (sys_check_args(callh, argv, name, 0, 0)) vpi_control(vpiFinish, 1); + return 0; +} + static PLI_INT32 sys_end_of_compile(p_cb_data cb_data) { (void)cb_data; /* Parameter is not used. */ @@ -2434,6 +2507,16 @@ void sys_display_register(void) res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiStringFunc; + tf_data.tfname = "$sformatf"; + tf_data.calltf = sys_display_calltf; + tf_data.compiletf = sys_sformatf_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$sformatf"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); + /*============================ timeformat */ tf_data.type = vpiSysTask; tf_data.tfname = "$timeformat"; diff --git a/vpi/system.sft b/vpi/system.sft index f3048198f..be082c85f 100644 --- a/vpi/system.sft +++ b/vpi/system.sft @@ -24,3 +24,5 @@ $table_model vpiSysFuncReal $ivl_string_method$len vpiSysFuncInt $ivl_string_method$to_vec vpiSysFuncVoid + +$sformatf vpiSysFuncString diff --git a/vvp/README.txt b/vvp/README.txt index 16de088f0..33bcbd377 100644 --- a/vvp/README.txt +++ b/vvp/README.txt @@ -840,6 +840,7 @@ instructions. The formats are: %vpi_call/i , ... ; %vpi_func , ... ; %vpi_func/r , ... ; + %vpi_func/s , ... ; The is an index into the string table. The indexed string is the source code file name where this call appears. The is diff --git a/vvp/lexor.lex b/vvp/lexor.lex index e161f0593..87f927623 100644 --- a/vvp/lexor.lex +++ b/vvp/lexor.lex @@ -235,6 +235,7 @@ static char* strdupnew(char const *str) "%vpi_call/i" { return K_vpi_call_i; } "%vpi_func" { return K_vpi_func; } "%vpi_func/r" { return K_vpi_func_r; } +"%vpi_func/s" { return K_vpi_func_s; } "%file_line" { return K_file_line; } /* Handle the specialized variable access functions. */ diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index a69e4f359..a9529373e 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -1241,6 +1241,7 @@ stack when the call returns. * %vpi_func [, ...] { } * %vpi_func/r [, ...] { } +* %vpi_func/s [, ...] { } This instruction is similar to %vpi_call, except that it is for calling system functions. The difference here is the return value from diff --git a/vvp/parse.y b/vvp/parse.y index de29c4750..832c53c98 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -100,7 +100,7 @@ static struct __vpiModPath*modpath_dst = 0; %token K_VAR_QUEUE %token K_VAR_S K_VAR_STR K_VAR_I K_VAR_R K_VAR_2S K_VAR_2U %token K_vpi_call K_vpi_call_w K_vpi_call_i -%token K_vpi_func K_vpi_func_r +%token K_vpi_func K_vpi_func_r K_vpi_func_s %token K_ivl_version K_ivl_delay_selection %token K_vpi_module K_vpi_time_precision K_file_names K_file_line %token K_PORT_INPUT K_PORT_OUTPUT K_PORT_INOUT K_PORT_MIXED K_PORT_NODIR @@ -658,6 +658,10 @@ statement { compile_vpi_func_call($1, $5, -vpiRealVal, 0, $3, $4, $6.argc, $6.argv, $8, $9, $10); } + | label_opt K_vpi_func_s T_NUMBER T_NUMBER T_STRING + argument_opt '{' T_NUMBER T_NUMBER T_NUMBER '}' ';' + { compile_vpi_func_call($1, $5, -vpiStringVal, 0, $3, $4, + $6.argc, $6.argv, $8, $9, $10); } /* Scope statements come in two forms. There are the scope declaration and the scope recall. The declarations create the diff --git a/vvp/vpi_tasks.cc b/vvp/vpi_tasks.cc index 4f35903c7..31368b391 100644 --- a/vvp/vpi_tasks.cc +++ b/vvp/vpi_tasks.cc @@ -143,54 +143,25 @@ static vpiHandle systask_iter(int, vpiHandle ref) } struct systask_def : public __vpiSysTaskCall { - inline systask_def() { } - int get_type_code(void) const { return vpiSysTaskCall; } - int vpi_get(int code) { return systask_get(code, this); } - char*vpi_get_str(int code) { return systask_get_str(code, this); } - vpiHandle vpi_handle(int code) { return systask_handle(code, this); } - vpiHandle vpi_iterate(int code){ return systask_iter(code, this); } + virtual ~systask_def() {}; + virtual int get_type_code(void) const { return vpiSysTaskCall; } + virtual int vpi_get(int code) { return systask_get(code, this); } + virtual char*vpi_get_str(int code) { return systask_get_str(code, this); } + virtual vpiHandle vpi_handle(int code) { return systask_handle(code, this); } + virtual vpiHandle vpi_iterate(int code){ return systask_iter(code, this); } }; -static vpiHandle sysfunc_put_rnet_value(vpiHandle ref, p_vpi_value vp, int) -{ - struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); +struct sysfunc_def : public systask_def { + virtual ~sysfunc_def() {}; + virtual int get_type_code(void) const { return vpiSysFuncCall; } + virtual int vpi_get(int code) { return sysfunc_get(code, this); } +}; - rfp->put_value = true; - - double val; - switch (vp->format) { - - case vpiRealVal: - val = vp->value.real; - break; - - default: - val = 0.0; - fprintf(stderr, "Unsupported format %d.\n", (int)vp->format); - assert(0); - } - - rfp->fnet->send_real(val, vthread_get_wt_context()); - - return 0; -} - -static vpiHandle sysfunc_put_no_value(vpiHandle, p_vpi_value, int) -{ - return 0; -} - -struct sysfunc_real : public __vpiSysTaskCall { - inline sysfunc_real() { } - int get_type_code(void) const { return vpiSysFuncCall; } - int vpi_get(int code) { return sysfunc_get(code, this); } - char* vpi_get_str(int code) { return systask_get_str(code, this); } +struct sysfunc_real : public sysfunc_def { vpiHandle vpi_put_value(p_vpi_value val, int flags); - vpiHandle vpi_handle(int code) - { return systask_handle(code, this); } - vpiHandle vpi_iterate(int code) - { return systask_iter(code, this); } + inline double return_value() const { return return_value_; } + private: double return_value_; }; @@ -211,18 +182,53 @@ vpiHandle sysfunc_real::vpi_put_value(p_vpi_value vp, int) return 0; } -class sysfunc_vec4 : public __vpiSysTaskCall { +struct sysfunc_str : public sysfunc_def { + int vpi_get(int code); + vpiHandle vpi_put_value(p_vpi_value val, int flags); + inline const std::string& return_value() const { return return_value_; }; + + private: + std::string return_value_; +}; + +int sysfunc_str::vpi_get(int code) +{ + switch (code) { + case vpiSize: + return return_value_.size(); + + case vpiLineNo: + return lineno; + + case vpiUserDefn: + return defn->is_user_defn; + + default: + return vpiUndefined; + } +} + +vpiHandle sysfunc_str::vpi_put_value(p_vpi_value vp, int) +{ + put_value = true; + + switch (vp->format) { + case vpiStringVal: + return_value_ = std::string(vp->value.str); + break; + default: + fprintf(stderr, "Unsupported format %d.\n", (int)vp->format); + assert(0); + } + + return 0; +} + +class sysfunc_vec4 : public sysfunc_def { public: explicit inline sysfunc_vec4(unsigned wid): return_value_(wid, BIT4_X) { } - int get_type_code(void) const { return vpiSysFuncCall; } int vpi_get(int code); - char* vpi_get_str(int code) { return systask_get_str(code, this); } vpiHandle vpi_put_value(p_vpi_value val, int flags); - vpiHandle vpi_handle(int code) - { return systask_handle(code, this); } - vpiHandle vpi_iterate(int code) - { return systask_iter(code, this); } - inline const vvp_vector4_t& return_value() const { return return_value_; } private: @@ -232,7 +238,6 @@ class sysfunc_vec4 : public __vpiSysTaskCall { vpiHandle put_value_vector_(p_vpi_value vp); vpiHandle put_value_time_(p_vpi_value vp); - private: vvp_vector4_t return_value_; }; @@ -388,48 +393,15 @@ vpiHandle sysfunc_vec4::vpi_put_value(p_vpi_value vp, int) return 0; } -struct sysfunc_4net : public __vpiSysTaskCall { +struct sysfunc_4net : public sysfunc_def { explicit inline sysfunc_4net(unsigned wid) : vwid_(wid) { } - int get_type_code(void) const { return vpiSysFuncCall; } int vpi_get(int code); - char* vpi_get_str(int code) { return systask_get_str(code, this); } vpiHandle vpi_put_value(p_vpi_value val, int flags); - vpiHandle vpi_handle(int code) - { return systask_handle(code, this); } - vpiHandle vpi_iterate(int code) - { return systask_iter(code, this); } private: unsigned vwid_; }; -struct sysfunc_rnet : public __vpiSysTaskCall { - inline sysfunc_rnet() { } - int get_type_code(void) const { return vpiSysFuncCall; } - int vpi_get(int code) { return sysfunc_get(code, this); } - char* vpi_get_str(int code) { return systask_get_str(code, this); } - vpiHandle vpi_put_value(p_vpi_value val, int flags) - { return sysfunc_put_rnet_value(this, val, flags); } - vpiHandle vpi_handle(int code) - { return systask_handle(code, this); } - vpiHandle vpi_iterate(int code) - { return systask_iter(code, this); } -}; - -struct sysfunc_no : public __vpiSysTaskCall { - inline sysfunc_no() { } - int get_type_code(void) const { return vpiSysFuncCall; } - int vpi_get(int code) { return sysfunc_get(code, this); } - char* vpi_get_str(int code) { return systask_get_str(code, this); } - vpiHandle vpi_put_value(p_vpi_value val, int flags) - { return sysfunc_put_no_value(this, val, flags); } - vpiHandle vpi_handle(int code) - { return systask_handle(code, this); } - vpiHandle vpi_iterate(int code) - { return systask_iter(code, this); } -}; - - // support getting vpiSize for a system function call int sysfunc_4net::vpi_get(int code) { @@ -547,6 +519,41 @@ vpiHandle sysfunc_4net::vpi_put_value(p_vpi_value vp, int) return 0; } +struct sysfunc_rnet : public sysfunc_def { + vpiHandle vpi_put_value(p_vpi_value val, int flags); +}; + +vpiHandle sysfunc_rnet::vpi_put_value(p_vpi_value vp, int) +{ + put_value = true; + + double value; + switch (vp->format) { + + case vpiRealVal: + value = vp->value.real; + break; + + default: + value = 0.0; + fprintf(stderr, "Unsupported format %d.\n", (int)vp->format); + assert(0); + } + + fnet->send_real(value, vthread_get_wt_context()); + + return 0; +} + +struct sysfunc_no : public sysfunc_def { + vpiHandle vpi_put_value(p_vpi_value val, int flags); +}; + +vpiHandle sysfunc_no::vpi_put_value(p_vpi_value, int) +{ + return 0; +} + /* **** Manipulate the internal data structures. **** */ @@ -845,6 +852,9 @@ vpiHandle vpip_build_vpi_call(const char*name, int val_code, unsigned return_wid } else if (val_code == -vpiVectorVal) { obj = new sysfunc_vec4(return_width); + } else if (val_code == -vpiStringVal) { + obj = new sysfunc_str; + } else if (val_code == 0 && fnet == 0) { obj = new sysfunc_no; @@ -957,12 +967,15 @@ void vpip_execute_vpi_call(vthread_t thr, vpiHandle ref) if (vpip_cur_task->string_stack > 0) vthread_pop_str(thr, vpip_cur_task->string_stack); - /* If the function has a real value, then push the value - to the thread stack. */ + /* If the function returns a value, then push the value + to the appropriate thread stack. */ if (sysfunc_real*func_real = dynamic_cast(ref)) { - vthread_push_real(thr, func_real->return_value_); + vthread_push_real(thr, func_real->return_value()); } - if (sysfunc_vec4*func_vec4 = dynamic_cast(ref)) { + else if (sysfunc_str*func_string = dynamic_cast(ref)) { + vthread_push_str(thr, func_string->return_value()); + } + else if (sysfunc_vec4*func_vec4 = dynamic_cast(ref)) { vthread_push_vec4(thr, func_vec4->return_value()); } } diff --git a/vvp/vthread.cc b/vvp/vthread.cc index aa5d87a9d..c8304cb5e 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -346,6 +346,11 @@ void vthread_push_real(struct vthread_s*thr, double val) thr->push_real(val); } +void vthread_push_str(struct vthread_s*thr, const string&val) +{ + thr->push_str(val); +} + void vthread_pop_vec4(struct vthread_s*thr, unsigned depth) { thr->pop_vec4(depth); diff --git a/vvp/vthread.h b/vvp/vthread.h index 7e9af3031..4df387128 100644 --- a/vvp/vthread.h +++ b/vvp/vthread.h @@ -113,6 +113,7 @@ extern vvp_context_item_t vthread_get_rd_context_item(unsigned context_idx); * Access value stacks from thread space. */ extern void vthread_push_vec4(struct vthread_s*thr, const vvp_vector4_t&val); +extern void vthread_push_str(struct vthread_s*thr, const std::string&val); extern void vthread_push_real(struct vthread_s*thr, double val); extern void vthread_pop_vec4(struct vthread_s*thr, unsigned count);