diff --git a/Makefile.in b/Makefile.in index 26f2f13ef..8d1761d92 100644 --- a/Makefile.in +++ b/Makefile.in @@ -108,13 +108,13 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \ elab_scope.o elab_sig.o elab_sig_analog.o emit.o eval.o eval_attrib.o \ eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \ load_module.o netlist.o netmisc.o nettypes.o net_analog.o net_assign.o \ - net_design.o \ + net_design.o netdarray.o \ netenum.o netstruct.o net_event.o net_expr.o net_func.o net_func_eval.o \ net_link.o net_modulo.o \ net_nex_input.o net_nex_output.o net_proc.o net_scope.o net_tran.o \ net_udp.o pad_to_width.o parse.o parse_misc.o pform.o pform_analog.o \ - pform_disciplines.o pform_dump.o pform_pclass.o pform_struct_type.o \ - pform_types.o \ + pform_disciplines.o pform_dump.o pform_pclass.o pform_string_type.o \ + pform_struct_type.o pform_types.o \ symbol_search.o sync.o sys_funcs.o verinum.o verireal.o target.o \ Attrib.o HName.o Module.o PClass.o PDelays.o PEvent.o PExpr.o PGate.o \ PGenerate.o PScope.o PSpec.o PTask.o PUdp.o PFunction.o PWire.o \ diff --git a/PExpr.cc b/PExpr.cc index 7cbc649a4..3cc8766c2 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -371,6 +371,16 @@ bool PEIdent::has_aa_term(Design*des, NetScope*scope) const return false; } +PENew::PENew(PExpr*size_expr) +: size_(size_expr) +{ +} + +PENew::~PENew() +{ + delete size_; +} + PENumber::PENumber(verinum*vp) : value_(vp) { diff --git a/PExpr.h b/PExpr.h index 98a16e14a..8f6e3778c 100644 --- a/PExpr.h +++ b/PExpr.h @@ -367,6 +367,8 @@ class PEIdent : public PExpr { bool elaborate_lval_net_packed_member_(Design*, NetScope*, NetAssign_*, const perm_string&) const; + bool elaborate_lval_darray_bit_(Design*, NetScope*, + NetAssign_*) const; private: NetExpr*elaborate_expr_param_(Design*des, @@ -439,6 +441,23 @@ class PEIdent : public PExpr { long&midx, long&lidx) const; }; +class PENew : public PExpr { + + public: + explicit PENew (PExpr*s); + ~PENew(); + + virtual void dump(ostream&) const; + virtual unsigned test_width(Design*des, NetScope*scope, + width_mode_t&mode); + virtual NetExpr*elaborate_expr(Design*des, NetScope*, + unsigned expr_wid, + unsigned flags) const; + + private: + PExpr*size_; +}; + class PENumber : public PExpr { public: @@ -717,8 +736,17 @@ class PECallFunction : public PExpr { bool check_call_matches_definition_(Design*des, NetScope*dscope) const; + NetExpr* cast_to_width_(NetExpr*expr, unsigned wid) const; + NetExpr*elaborate_expr_method_(Design*des, NetScope*scope, + unsigned expr_wid) const; +#if 0 + NetExpr*elaborate_expr_string_method_(Design*des, NetScope*scope) const; + NetExpr*elaborate_expr_enum_method_(Design*des, NetScope*scope, + unsigned expr_wid) const; +#endif + NetExpr* elaborate_sfunc_(Design*des, NetScope*scope, unsigned expr_wid, unsigned flags) const; @@ -726,6 +754,8 @@ class PECallFunction : public PExpr { unsigned expr_wid) const; unsigned test_width_sfunc_(Design*des, NetScope*scope, width_mode_t&mode); + unsigned test_width_method_(Design*des, NetScope*scope, + width_mode_t&mode); }; /* diff --git a/PWire.h b/PWire.h index 52c761821..1dc1099f2 100644 --- a/PWire.h +++ b/PWire.h @@ -33,6 +33,7 @@ class ostream; class PExpr; class Design; +class netdarray_t; /* * The different type of PWire::set_range() calls. diff --git a/Statement.h b/Statement.h index 48c58a800..f812928c9 100644 --- a/Statement.h +++ b/Statement.h @@ -107,6 +107,9 @@ class PAssign_ : public Statement { NetExpr* elaborate_rval_(Design*, NetScope*, unsigned lv_width, ivl_variable_type_t type) const; + NetExpr* elaborate_rval_obj_(Design*, NetScope*, + ivl_variable_type_t type) const; + PExpr* delay_; PEventStatement*event_; PExpr* count_; @@ -207,6 +210,8 @@ class PCallTask : public Statement { NetProc* elaborate_sys(Design*des, NetScope*scope) const; NetProc* elaborate_usr(Design*des, NetScope*scope) const; + NetProc*elaborate_method_(Design*des, NetScope*scope) const; + pform_name_t path_; vector parms_; }; diff --git a/design_dump.cc b/design_dump.cc index dd2a4555e..488553938 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -28,6 +28,7 @@ # include "netlist.h" # include "compiler.h" # include "discipline.h" +# include "netdarray.h" # include "ivl_assert.h" # include "PExpr.h" @@ -104,6 +105,9 @@ ostream& operator << (ostream&o, ivl_variable_type_t val) case IVL_VT_STRING: o << "string"; break; + case IVL_VT_DARRAY: + o << "darray"; + break; } return o; } @@ -193,11 +197,21 @@ void NetDelaySrc::dump(ostream&o, unsigned ind) const dump_node_pins(o, ind+4); } +static inline ostream&operator<<(ostream&out, const netrange_t&that) +{ + if (that.defined()) + out << "[" << that.get_msb() << ":" << that.get_lsb() << "]"; + else + out << "[]"; + + return out; +} + ostream&operator<<(ostream&out, const list&rlist) { for (list::const_iterator cur = rlist.begin() ; cur != rlist.end() ; ++cur) { - out << "[" << cur->msb << ":" << cur->lsb << "]"; + out << *cur; } return out; } @@ -206,7 +220,7 @@ ostream&operator<<(ostream&out, const vector&rlist) { for (vector::const_iterator cur = rlist.begin() ; cur != rlist.end() ; ++cur) { - out << "[" << cur->msb << ":" << cur->lsb << "]"; + out << *cur; } return out; } @@ -244,7 +258,11 @@ void NetNet::dump_net(ostream&o, unsigned ind) const if (ivl_discipline_t dis = get_discipline()) o << " discipline=" << dis->name(); - o << " packed dims: " << packed_dims_; + if (netdarray_t*darray = darray_type()) + o << " dynamic array of " << darray->data_type(); + + if (!packed_dims_.empty()) + o << " packed dims: " << packed_dims_; o << " (eref=" << peek_eref() << ", lref=" << peek_lref() << ")"; if (scope()) @@ -1287,12 +1305,12 @@ void NetSTask::dump(ostream&o, unsigned ind) const { o << setw(ind) << "" << name_; - if (parms_.count() > 0) { + if (parms_.size() > 0) { o << "("; if (parms_[0]) parms_[0]->dump(o); - for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) { + for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) { o << ", "; if (parms_[idx]) parms_[idx]->dump(o); @@ -1422,7 +1440,7 @@ void NetEConcat::dump(ostream&o) const else o << "{"; - for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) { + for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) { if (parms_[idx]) o << ", " << *parms_[idx]; else diff --git a/dup_expr.cc b/dup_expr.cc index c1258eba6..64c832891 100644 --- a/dup_expr.cc +++ b/dup_expr.cc @@ -110,10 +110,10 @@ NetEBShift* NetEBShift::dup_expr() const NetEConcat* NetEConcat::dup_expr() const { - NetEConcat*dup = new NetEConcat(parms_.count(), repeat_); + NetEConcat*dup = new NetEConcat(parms_.size(), repeat_, expr_type_); ivl_assert(*this, dup); dup->set_line(*this); - for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) + for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) if (parms_[idx]) { NetExpr*tmp = parms_[idx]->dup_expr(); ivl_assert(*this, tmp); diff --git a/elab_expr.cc b/elab_expr.cc index f323e8351..2a94d16ee 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -29,6 +29,7 @@ # include "netenum.h" # include "discipline.h" # include "netmisc.h" +# include "netdarray.h" # include "netstruct.h" # include "util.h" # include "ivl_assert.h" @@ -89,6 +90,7 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, switch (lv_type) { case IVL_VT_REAL: case IVL_VT_STRING: + case IVL_VT_DARRAY: break; case IVL_VT_BOOL: case IVL_VT_LOGIC: @@ -1021,6 +1023,15 @@ unsigned PECallFunction::test_width(Design*des, NetScope*scope, return expr_width_; } + if (test_width_method_(des, scope, mode)) { + if (debug_elaborate) + cerr << get_fileline() << ": debug: test_width " + << "of method returns width " << expr_width_ + << ", type=" << expr_type_ + << "." << endl; + return expr_width_; + } + if (debug_elaborate) cerr << get_fileline() << ": debug: test_width " << "cannot find definition of " << path_ @@ -1050,6 +1061,46 @@ unsigned PECallFunction::test_width(Design*des, NetScope*scope, return 0; } +unsigned PECallFunction::test_width_method_(Design*des, NetScope*scope, + width_mode_t&mode) +{ + if (!gn_system_verilog()) + return 0; + + // This is only useful if the path is at least 2 elements. For + // example, foo.bar() is a method, bar() is not. + if (path_.size() < 2) + return 0; + + pform_name_t use_path = path_; + perm_string method_name = peek_tail_name(use_path); + use_path.pop_back(); + + NetNet *net; + const NetExpr *par; + NetEvent *eve; + const NetExpr *ex1, *ex2; + + symbol_search(this, des, scope, use_path, + net, par, eve, ex1, ex2); + + if (net == 0) + return 0; + + netdarray_t*darray = net->darray_type(); + + // function int size() + if (darray && method_name == "size") { + expr_type_ = IVL_VT_BOOL; + expr_width_ = 32; + min_width_ = expr_width_; + signed_flag_= true; + return expr_width_; + } + + return 0; +} + NetExpr*PECallFunction::cast_to_width_(NetExpr*expr, unsigned wid) const { /* If the expression is a const, then replace it with a new @@ -1582,43 +1633,11 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, return elaborate_access_func_(des, scope, access_nature, expr_wid); - // Maybe this is a method attached to an enumeration name? If - // this is system verilog, then test to see if the name is - // really a method attached to an object. - if (gn_system_verilog() && path_.size() >= 2) { - pform_name_t use_path = path_; - perm_string method_name = peek_tail_name(use_path); - use_path.pop_back(); - - NetNet *net; - const NetExpr *par; - NetEvent *eve; - const NetExpr *ex1, *ex2; - - symbol_search(this, des, scope, use_path, - net, par, eve, ex1, ex2); - - // Check to see if we have a net and if so is it an - // enumeration? If so then check to see if this is an - // enumeration method call. - if (net != 0) { - if (netenum_t*netenum = net->enumeration()) { - // We may need the net expression for the - // enumeration variable so get it. - NetESignal*expr = new NetESignal(net); - expr->set_line(*this); - // This expression cannot be a select! - assert(use_path.back().index.empty()); - - PExpr*tmp = parms_.size() ? parms_[0] : 0; - return check_for_enum_methods(this, des, scope, - netenum, use_path, - method_name, expr, - expr_wid, tmp, - parms_.size()); - } - - } + // Maybe this is a method attached to a signal? If this + // is SystemVerilog then try that possibility. + if (gn_system_verilog()) { + NetExpr*tmp = elaborate_expr_method_(des, scope, expr_wid); + if (tmp) return tmp; } // Nothing was found so report this as an error. @@ -1759,6 +1778,64 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, return 0; } +NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, + unsigned expr_wid) const +{ + pform_name_t use_path = path_; + perm_string method_name = peek_tail_name(use_path); + use_path.pop_back(); + + NetNet *net; + const NetExpr *par; + NetEvent *eve; + const NetExpr *ex1, *ex2; + + symbol_search(this, des, scope, use_path, + net, par, eve, ex1, ex2); + + if (net == 0) + return 0; + + if (net->data_type() == IVL_VT_STRING) { + + if (method_name == "len") { + NetESFunc*sys_expr = new NetESFunc("$ivl_string_method$len", + IVL_VT_BOOL, 32, 1); + sys_expr->parm(0, new NetESignal(net)); + return sys_expr; + } + } + + if (netenum_t*netenum = net->enumeration()) { + // We may need the net expression for the + // enumeration variable so get it. + NetESignal*expr = new NetESignal(net); + expr->set_line(*this); + // This expression cannot be a select! + assert(use_path.back().index.empty()); + + PExpr*tmp = parms_.size() ? parms_[0] : 0; + return check_for_enum_methods(this, des, scope, + netenum, use_path, + method_name, expr, + expr_wid, tmp, + parms_.size()); + } + + if (net->darray_type()) { + + if (method_name == "size") { + NetESFunc*sys_expr = new NetESFunc("$ivl_darray_method$size", + IVL_VT_BOOL, 32, 1); + sys_expr->parm(0, new NetESignal(net)); + sys_expr->set_line(*this); + return sys_expr; + } + } + + return 0; +} + unsigned PECastSize::test_width(Design*des, NetScope*scope, width_mode_t&) { expr_width_ = size_; @@ -1782,15 +1859,36 @@ NetExpr* PECastSize::elaborate_expr(Design*des, NetScope*scope, unsigned PEConcat::test_width(Design*des, NetScope*scope, width_mode_t&) { expr_width_ = 0; + enum {NO, MAYBE, YES} expr_is_string = MAYBE; for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) { + // Add in the width of this sub-expression. expr_width_ += parms_[idx]->test_width(des, scope, width_modes_[idx]); + + // If we already know this is not a string, then move on. + if (expr_is_string == NO) + continue; + + // If this expression is a string, then the + // concatenation is a string until we find a reason to + // deny it. + if (parms_[idx]->expr_type()==IVL_VT_STRING) { + expr_is_string = YES; + continue; + } + + // If this is a string literal, then this may yet be a string. + if (dynamic_cast (parms_[idx])) + continue; + + // Failed to allow a string result. + expr_is_string = NO; } - expr_type_ = IVL_VT_LOGIC; + expr_type_ = (expr_is_string==YES)? IVL_VT_STRING : IVL_VT_LOGIC; signed_flag_ = false; - /* If there is a repeat expression, then evaluate the constant - value and set the repeat count. */ + // If there is a repeat expression, then evaluate the constant + // value and set the repeat count. if (repeat_ && (scope != tested_scope_)) { NetExpr*tmp = elab_and_eval(des, scope, repeat_, -1, true); if (tmp == 0) return 0; @@ -1919,7 +2017,7 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope, } /* Make the empty concat expression. */ - NetEConcat*concat = new NetEConcat(parm_cnt, repeat_count_); + NetEConcat*concat = new NetEConcat(parm_cnt, repeat_count_, expr_type_); concat->set_line(*this); /* Remove any zero width constants. */ @@ -2214,6 +2312,21 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) ivl_assert(*this, 0); } + if (netdarray_t*darray = net? net->darray_type() : 0) { + if (use_sel == index_component_t::SEL_BIT) { + expr_type_ = darray->data_type(); + expr_width_ = darray->vector_width(); + min_width_ = expr_width_; + signed_flag_ = net->get_signed(); + } else { + expr_type_ = net->data_type(); + expr_width_ = net->vector_width(); + min_width_ = expr_width_; + signed_flag_ = net->get_signed(); + } + return expr_width_; + } + if (use_width != UINT_MAX) { expr_type_ = IVL_VT_LOGIC; // Assume bit/parts selects are logic expr_width_ = use_width; @@ -2228,8 +2341,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) expr_type_ = net->data_type(); expr_width_ = net->vector_width(); min_width_ = expr_width_; - signed_flag_ = net->get_signed(); - + signed_flag_ = net->get_signed(); return expr_width_; } @@ -3386,7 +3498,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, // We want the last range, which is where we work. const netrange_t&rng = packed.back(); - if (rng.msb < rng.lsb) { + if (rng.get_msb() < rng.get_lsb()) { offset = -wid + 1; } @@ -3566,6 +3678,20 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, NetExpr*mux = elab_and_eval(des, scope, index_tail.msb, -1, need_const); + if (netdarray_t*darray = net->sig()->darray_type()) { + // Special case: This is a select of a dynamic + // array. Generate a NetESelect and attach it to + // the NetESignal. This should be interpreted as + // an array word select downstream. + if (debug_elaborate) { + cerr << get_fileline() << ": debug: " + << "Bit select of a dynamic array becomes NetESelect." << endl; + } + NetESelect*res = new NetESelect(net, mux, darray->vector_width()); + res->set_line(*net); + return res; + } + // If the bit select is constant, then treat it similar // to the part select, so that I save the effort of // making a mux part in the netlist. @@ -3618,6 +3744,32 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, return res; } + if (net->sig()->data_type()==IVL_VT_STRING && (msv < 0)) { + // Special case: This is a constant bit select of + // a string, and the index is < 0. For example: + // string foo; + // ... foo[-1] ... + // This is known to be 8'h00. + NetEConst*tmp = make_const_0(8); + tmp->set_line(*this); + delete mux; + return tmp; + } + + if (net->sig()->data_type()==IVL_VT_STRING) { + // Special case: This is a select of a string + // variable. Generate a NetESelect and attach it + // to the NetESignal. This should be interpreted + // as a character select downstream. + if (debug_elaborate) { + cerr << get_fileline() << ": debug: " + << "Bit select of string becomes NetESelect." << endl; + } + NetESelect*res = new NetESelect(net, mux, 8); + res->set_line(*net); + return res; + } + long idx = net->sig()->sb_to_idx(prefix_indices,msv); if (idx >= (long)net->vector_width() || idx < 0) { @@ -3756,6 +3908,28 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope, return node; } +unsigned PENew::test_width(Design*des, NetScope*, width_mode_t&) +{ + expr_type_ = IVL_VT_DARRAY; + expr_width_ = 1; + min_width_ = 1; + signed_flag_= false; + return 1; +} + +NetExpr* PENew::elaborate_expr(Design*des, NetScope*scope, + unsigned, unsigned flags) const +{ + width_mode_t mode = LOSSLESS; + unsigned use_wid = size_->test_width(des, scope, mode); + NetExpr*size = size_->elaborate_expr(des, scope, use_wid, flags); + NetESFunc*tmp = new NetESFunc("$ivl_darray_method$new", + IVL_VT_DARRAY, 1, 1); + tmp->set_line(*this); + tmp->parm(0, size); + return tmp; +} + unsigned PENumber::test_width(Design*, NetScope*, width_mode_t&mode) { expr_type_ = IVL_VT_LOGIC; diff --git a/elab_lval.cc b/elab_lval.cc index f3e56ed82..71421e742 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -257,9 +257,15 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, if (use_sel == index_component_t::SEL_BIT) { - NetAssign_*lv = new NetAssign_(reg); - elaborate_lval_net_bit_(des, scope, lv); - return lv; + if (reg->darray_type()) { + NetAssign_*lv = new NetAssign_(reg); + elaborate_lval_darray_bit_(des, scope, lv); + return lv; + } else { + NetAssign_*lv = new NetAssign_(reg); + elaborate_lval_net_bit_(des, scope, lv); + return lv; + } } ivl_assert(*this, use_sel == index_component_t::SEL_NONE); @@ -413,6 +419,22 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des, lv->set_part(mux, lwid); } + } else if (reg->data_type() == IVL_VT_STRING) { + // Special case: This is a select of a string + // variable. The target of the assignment is a character + // select of a string. Force the r-value to be an 8bit + // vector and set the "part" to be the character select + // expression. The code generator knows what to do with + // this. + if (debug_elaborate) { + cerr << get_fileline() << ": debug: " + << "Bit select of string becomes character select." << endl; + } + if (mux) + lv->set_part(mux, 8); + else + lv->set_part(new NetEConst(verinum(lsb)), 8); + } else if (mux) { // Non-constant bit mux. Correct the mux for the range // of the vector, then set the l-value part select @@ -442,6 +464,26 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des, return true; } +bool PEIdent::elaborate_lval_darray_bit_(Design*des, NetScope*scope, NetAssign_*lv)const +{ + const name_component_t&name_tail = path_.back(); + ivl_assert(*this, !name_tail.index.empty()); + + // For now, only support single-dimension dynamic arrays. + ivl_assert(*this, name_tail.index.size() == 1); + + const index_component_t&index_tail = name_tail.index.back(); + ivl_assert(*this, index_tail.msb != 0); + ivl_assert(*this, index_tail.lsb == 0); + + // Evaluate the select expression... + NetExpr*mux = elab_and_eval(des, scope, index_tail.msb, -1); + + lv->set_word(mux); + + return true; +} + bool PEIdent::elaborate_lval_net_part_(Design*des, NetScope*scope, NetAssign_*lv) const @@ -558,9 +600,9 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, // We want the last range, which is where we work. const netrange_t&rng = packed.back(); - if (((rng.msb < rng.lsb) && + if (((rng.get_msb() < rng.get_lsb()) && use_sel == index_component_t::SEL_IDX_UP) || - ((rng.msb > rng.lsb) && + ((rng.get_msb() > rng.get_lsb()) && use_sel == index_component_t::SEL_IDX_DO)) { offset = -wid + 1; } diff --git a/elab_sig.cc b/elab_sig.cc index a795a3a33..232fc0b0d 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -32,7 +32,9 @@ # include "compiler.h" # include "netlist.h" # include "netmisc.h" +# include "netenum.h" # include "netstruct.h" +# include "netdarray.h" # include "util.h" # include "ivl_assert.h" @@ -821,10 +823,10 @@ static bool evaluate_ranges(Design*des, NetScope*scope, for (list::const_iterator cur = rlist.begin() ; cur != rlist.end() ; ++cur) { - netrange_t lrng; + long use_msb, use_lsb; NetExpr*texpr = elab_and_eval(des, scope, cur->first, -1, true); - if (! eval_as_long(lrng.msb, texpr)) { + if (! eval_as_long(use_msb, texpr)) { cerr << cur->first->get_fileline() << ": error: " "Range expressions must be constant." << endl; cerr << cur->first->get_fileline() << " : " @@ -837,7 +839,7 @@ static bool evaluate_ranges(Design*des, NetScope*scope, delete texpr; texpr = elab_and_eval(des, scope, cur->second, -1, true); - if (! eval_as_long(lrng.lsb, texpr)) { + if (! eval_as_long(use_lsb, texpr)) { cerr << cur->second->get_fileline() << ": error: " "Range expressions must be constant." << endl; cerr << cur->second->get_fileline() << " : " @@ -849,7 +851,7 @@ static bool evaluate_ranges(Design*des, NetScope*scope, delete texpr; - llist.push_back(lrng); + llist.push_back(netrange_t(use_msb, use_lsb)); } return bad_msb | bad_lsb; @@ -899,9 +901,9 @@ bool test_ranges_eeq(const list&lef, const list&rig) list::const_iterator lcur = lef.begin(); list::const_iterator rcur = rig.begin(); while (lcur != lef.end()) { - if (lcur->msb != rcur->msb) + if (lcur->get_msb() != rcur->get_msb()) return false; - if (lcur->lsb != rcur->lsb) + if (lcur->get_lsb() != rcur->get_lsb()) return false; ++ lcur; @@ -1049,12 +1051,26 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const listunpacked_dimensions; + netdarray_t*netarray = 0; for (list::const_iterator cur = unpacked_.begin() ; cur != unpacked_.end() ; ++cur) { PExpr*use_lidx = cur->first; PExpr*use_ridx = cur->second; - assert(use_lidx && use_ridx); + + // Special case: If we encounter an undefined + // dimensions, then turn this into a dynamic array and + // put all the packed dimensions there. + if (use_lidx==0 && use_ridx==0) { + ivl_assert(*this, netarray==0); + netarray = new netdarray_t(packed_dimensions, data_type_, wid); + packed_dimensions.clear(); + continue; + } + + // Cannot handle dynamic arrays of arrays yet. + ivl_assert(*this, netarray==0); + ivl_assert(*this, use_lidx && use_ridx); NetExpr*lexp = elab_and_eval(des, scope, use_lidx, -1, true); NetExpr*rexp = elab_and_eval(des, scope, use_ridx, -1, true); @@ -1157,6 +1173,34 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const sig = new NetNet(scope, name_, wtype, use_type); + } else if (enum_type_) { + ivl_assert(*this, struct_type_ == 0); + ivl_assert(*this, ! enum_type_->names->empty()); + list::const_iterator sample_name = enum_type_->names->begin(); + netenum_t*use_enum = scope->enumeration_for_name(sample_name->name); + + if (debug_elaborate) { + cerr << get_fileline() << ": debug: Create signal " << wtype + << " enumeration " + << name_ << " in scope " << scope_path(scope) << endl; + } + + sig = new NetNet(scope, name_, wtype, packed_dimensions, unpacked_dimensions, use_enum); + + } else if (netarray) { + ivl_assert(*this, struct_type_==0); + ivl_assert(*this, enum_type_==0); + + if (debug_elaborate) { + cerr << get_fileline() << ": debug: Create signal " << wtype + << " dynamic array " + << name_ << " in scope " << scope_path(scope) << endl; + } + + ivl_assert(*this, packed_dimensions.empty()); + ivl_assert(*this, unpacked_dimensions.empty()); + sig = new NetNet(scope, name_, wtype, netarray); + } else { if (debug_elaborate) { cerr << get_fileline() << ": debug: Create signal " << wtype; @@ -1170,16 +1214,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const sig = new NetNet(scope, name_, wtype, packed_dimensions, unpacked_dimensions); } - // If this is an enumeration, then set the enumeration set for - // the new signal. This turns it into an enumeration. - if (enum_type_) { - ivl_assert(*this, struct_type_ == 0); - ivl_assert(*this, ! enum_type_->names->empty()); - list::const_iterator sample_name = enum_type_->names->begin(); - netenum_t*use_enum = scope->enumeration_for_name(sample_name->name); - sig->set_enumeration(use_enum); - } - if (wtype == NetNet::WIRE) sig->devirtualize_pins(); ivl_variable_type_t use_data_type = data_type_; diff --git a/elaborate.cc b/elaborate.cc index c777fb65a..7a24cb69b 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -2908,7 +2908,7 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const if ((parm_count== 1) && (parms_[0] == 0)) parm_count = 0; - svectoreparms (parm_count); + vectoreparms (parm_count); perm_string name = peek_tail_name(path_); @@ -2987,6 +2987,12 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const NetScope*task = des->find_task(scope, path_); if (task == 0) { + // Maybe this is a method attached to a signal? + if (gn_system_verilog()) { + NetProc*tmp = elaborate_method_(des, scope); + if (tmp) return tmp; + } + cerr << get_fileline() << ": error: Enable of unknown task " << "``" << path_ << "''." << endl; des->errors += 1; @@ -3169,6 +3175,39 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const return block; } +NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope) const +{ + pform_name_t use_path = path_; + perm_string method_name = peek_tail_name(use_path); + use_path.pop_back(); + + NetNet *net; + const NetExpr *par; + NetEvent *eve; + const NetExpr *ex1, *ex2; + + symbol_search(this, des, scope, use_path, + net, par, eve, ex1, ex2); + + if (net == 0) + return 0; + + // Is this a delete method for dynamic arrays? + if (net->darray_type() && method_name=="delete") { + NetESignal*sig = new NetESignal(net); + + vector argv (1); + argv[0] = sig; + + NetSTask*sys = new NetSTask("$ivl_darray_method$delete", + IVL_SFUNC_AS_TASK_IGNORE, argv); + sys->set_line(*this); + return sys; + } + + return 0; +} + /* * Elaborate a procedural continuous assign. This really looks very * much like other procedural assignments, at this point, but there diff --git a/eval_tree.cc b/eval_tree.cc index bb63ba09c..cb3edee8f 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -1127,7 +1127,7 @@ NetEConst* NetEConcat::eval_tree() } unsigned gap = 0; - for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) { + for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) { // Parameter not here? This is an error, but presumably // already caught and we are here just to catch more. @@ -1178,7 +1178,7 @@ NetEConst* NetEConcat::eval_tree() unsigned cur = 0; bool is_string_flag = true; - for (unsigned idx = parms_.count() ; idx > 0 ; idx -= 1) { + for (unsigned idx = parms_.size() ; idx > 0 ; idx -= 1) { NetEConst*expr = dynamic_cast(parms_[idx-1]); if (expr == 0) return 0; diff --git a/expr_synth.cc b/expr_synth.cc index d1877ecc7..6a791c3ae 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -702,11 +702,11 @@ NetNet* NetEBShift::synthesize(Design*des, NetScope*scope, NetExpr*root) NetNet* NetEConcat::synthesize(Design*des, NetScope*scope, NetExpr*root) { /* First, synthesize the operands. */ - unsigned num_parms = parms_.count(); - NetNet**tmp = new NetNet*[parms_.count()]; + unsigned num_parms = parms_.size(); + NetNet**tmp = new NetNet*[parms_.size()]; bool flag = true; ivl_variable_type_t data_type = IVL_VT_NO_TYPE; - for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) { + for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) { if (parms_[idx]->expr_width() == 0) { /* We need to synthesize a replication of zero. */ tmp[idx] = parms_[idx]->synthesize(des, scope, root); @@ -754,8 +754,8 @@ NetNet* NetEConcat::synthesize(Design*des, NetScope*scope, NetExpr*root) unsigned count_input_width = 0; unsigned cur_pin = 1; for (unsigned rpt = 0; rpt < repeat(); rpt += 1) { - for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) { - unsigned concat_item = parms_.count()-idx-1; + for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) { + unsigned concat_item = parms_.size()-idx-1; if (tmp[concat_item] == 0) continue; connect(concat->pin(cur_pin), tmp[concat_item]->pin(0)); cur_pin += 1; diff --git a/ivl_target.h b/ivl_target.h index 0639ca7e5..9d25bca35 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -435,6 +435,7 @@ typedef enum ivl_variable_type_e { IVL_VT_BOOL = 3, IVL_VT_LOGIC = 4, IVL_VT_STRING = 5, + IVL_VT_DARRAY = 6, /* Array (esp. dynamic array) */ IVL_VT_VECTOR = IVL_VT_LOGIC /* For compatibility */ } ivl_variable_type_t; @@ -813,6 +814,14 @@ extern unsigned ivl_event_lineno(ivl_event_t net); * conversion from signal units to vector units, so the result of * ivl_expr_oper1 should range from 0 to ivl_expr_width(). * + * This exprsesion is also used to implement string substrings. If the + * sub-expression (oper1) is IVL_VT_STRING, then the base expression + * (oper2) is a charaster address, with 0 the first address of the + * string, 1 the second, and so on. This is OPPOSITE how a part select + * of a string cast to a vector works, to be aware. The size of the + * expression is an even multiple of 8, and is 8 times the number of + * characters to pick. + * * - IVL_EX_SIGNAL * This expression references a signal vector. The ivl_expr_signal * function gets a handle for the signal that is referenced. The diff --git a/net_assign.cc b/net_assign.cc index 286f4cd30..b132fbcdc 100644 --- a/net_assign.cc +++ b/net_assign.cc @@ -20,6 +20,7 @@ # include "config.h" # include "netlist.h" +# include "netdarray.h" /* * NetAssign @@ -84,11 +85,25 @@ ivl_select_type_t NetAssign_::select_type() const unsigned NetAssign_::lwidth() const { + if (netdarray_t*darray = sig_->darray_type()) { + if (word_ == 0) + return 1; + else + return darray->vector_width(); + } + return lwid_; } ivl_variable_type_t NetAssign_::expr_type() const { + if (netdarray_t*darray = sig_->darray_type()) { + if (word_ == 0) + return IVL_VT_DARRAY; + else + return darray->data_type(); + } + return sig_->data_type(); } diff --git a/net_expr.cc b/net_expr.cc index b632693fa..4971bf037 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -184,18 +184,23 @@ bool NetEBShift::has_width() const return left_->has_width(); } -NetEConcat::NetEConcat(unsigned cnt, unsigned r) -: parms_(cnt), repeat_(r) +NetEConcat::NetEConcat(unsigned cnt, unsigned r, ivl_variable_type_t vt) +: parms_(cnt), repeat_(r), expr_type_(vt) { expr_width(0); } NetEConcat::~NetEConcat() { - for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) + for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) delete parms_[idx]; } +ivl_variable_type_t NetEConcat::expr_type() const +{ + return expr_type_; +} + bool NetEConcat::has_width() const { return true; @@ -203,7 +208,7 @@ bool NetEConcat::has_width() const void NetEConcat::set(unsigned idx, NetExpr*e) { - assert(idx < parms_.count()); + assert(idx < parms_.size()); assert(parms_[idx] == 0); parms_[idx] = e; expr_width( expr_width() + repeat_ * e->expr_width() ); diff --git a/net_nex_input.cc b/net_nex_input.cc index a47b60302..25b67e95e 100644 --- a/net_nex_input.cc +++ b/net_nex_input.cc @@ -56,7 +56,7 @@ NexusSet* NetEConcat::nex_input(bool rem_out) { if (parms_[0] == NULL) return NULL; NexusSet*result = parms_[0]->nex_input(rem_out); - for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) { + for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) { if (parms_[idx] == NULL) { delete result; return NULL; @@ -397,13 +397,13 @@ NexusSet* NetRepeat::nex_input(bool rem_out) */ NexusSet* NetSTask::nex_input(bool rem_out) { - if (parms_.count() == 0) + if (parms_.size() == 0) return new NexusSet; NexusSet*result; if (parms_[0]) result = parms_[0]->nex_input(rem_out); else result = new NexusSet; - for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) { + for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) { if (parms_[idx]) { NexusSet*tmp = parms_[idx]->nex_input(rem_out); result->add(*tmp); diff --git a/netarray.h b/netarray.h new file mode 100644 index 000000000..dcb02f0d1 --- /dev/null +++ b/netarray.h @@ -0,0 +1,48 @@ +#ifndef __netarray_H +#define __netarray_H +/* + * Copyright (c) 2012 Stephen Williams (steve@icarus.com) + * Copyright CERN 2012 / 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 + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "LineInfo.h" +# include + +class netarray_t : public LineInfo { + + public: + explicit netarray_t(const std::list&packed); + ~netarray_t(); + + unsigned packed_width() const; + + private: + std::list packed_dims_; + +}; + +inline netarray_t::netarray_t(const std::list&packed) +: packed_dims_(packed) +{ +} + +netarray_t::~netarray_t() +{ +} + +#endif diff --git a/netdarray.cc b/netdarray.cc new file mode 100644 index 000000000..e622beea9 --- /dev/null +++ b/netdarray.cc @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2012 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 + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "netdarray.h" + +using namespace std; + +netdarray_t::netdarray_t(const std::list&packed, + ivl_variable_type_t type, unsigned long wid) +: packed_dims_(packed), type_(type), width_(wid) +{ +} + +netdarray_t::~netdarray_t() +{ +} diff --git a/netdarray.h b/netdarray.h new file mode 100644 index 000000000..2fb1a6f8c --- /dev/null +++ b/netdarray.h @@ -0,0 +1,43 @@ +#ifndef __netdarray_H +#define __netdarray_H +/* + * Copyright (c) 2012 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 + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "nettypes.h" +# include "ivl_target.h" +# include + +class netdarray_t : public nettype_base_t { + + public: + explicit netdarray_t(const std::list&packed, + ivl_variable_type_t type, + unsigned long wid); + ~netdarray_t(); + + inline ivl_variable_type_t data_type() const { return type_; } + inline unsigned long vector_width(void) const { return width_; } + + private: + std::list packed_dims_; + ivl_variable_type_t type_; + unsigned long width_; +}; + +#endif diff --git a/netenum.h b/netenum.h index 81080f9e3..1179d6031 100644 --- a/netenum.h +++ b/netenum.h @@ -20,6 +20,7 @@ */ # include "ivl_target.h" +# include "nettypes.h" # include "verinum.h" # include "StringHeap.h" # include "LineInfo.h" @@ -28,7 +29,7 @@ class NetScope; -class netenum_t : public LineInfo { +class netenum_t : public LineInfo, public nettype_base_t { public: explicit netenum_t(ivl_variable_type_t base_type, bool signed_flag, diff --git a/netlist.cc b/netlist.cc index 03a393a00..554517d61 100644 --- a/netlist.cc +++ b/netlist.cc @@ -27,6 +27,8 @@ # include "compiler.h" # include "netlist.h" # include "netmisc.h" +# include "netdarray.h" +# include "netenum.h" # include "netstruct.h" # include "ivl_assert.h" @@ -465,7 +467,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins) : NetObj(s, n, 1), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), is_scalar_(false), local_flag_(false), - enumeration_(0), struct_type_(0), discipline_(0), + net_type_(0), discipline_(0), eref_count_(0), lref_count_(0), port_index_(-1) { @@ -515,7 +517,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, : NetObj(s, n, 1), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), is_scalar_(false), local_flag_(false), - enumeration_(0), struct_type_(0), discipline_(0), + net_type_(0), discipline_(0), eref_count_(0), lref_count_(0) { packed_dims_ = packed; @@ -548,6 +550,11 @@ static unsigned calculate_count(const list&unpacked) unsigned long sum = 1; for (list::const_iterator cur = unpacked.begin() ; cur != unpacked.end() ; ++cur) { + // Special case: If there are any undefined dimensions, + // then give up on trying to create pins for the net. + if (! cur->defined()) + return 0; + sum *= cur->width(); } @@ -559,11 +566,12 @@ static unsigned calculate_count(const list&unpacked) NetNet::NetNet(NetScope*s, perm_string n, Type t, const list&packed, - const list&unpacked) + const list&unpacked, + nettype_base_t*net_type) : NetObj(s, n, calculate_count(unpacked)), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), - is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(0), + is_scalar_(false), local_flag_(false), net_type_(net_type), discipline_(0), unpacked_dims_(unpacked.size()), eref_count_(0), lref_count_(0) { @@ -577,7 +585,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, ivl_assert(*this, s); if (pin_count() == 0) { - cerr << "Array too big " << unpacked << endl; + cerr << "Invalid array dimensions: " << unpacked << endl; ivl_assert(*this, 0); } @@ -621,7 +629,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, netstruct_t*ty) : NetObj(s, n, 1), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), - is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(ty), + is_scalar_(false), local_flag_(false), net_type_(ty), discipline_(0), eref_count_(0), lref_count_(0) { @@ -648,6 +656,36 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, netstruct_t*ty) s->add_signal(this); } +NetNet::NetNet(NetScope*s, perm_string n, Type t, netdarray_t*ty) +: NetObj(s, n, 1), + type_(t), port_type_(NOT_A_PORT), + data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), + is_scalar_(false), local_flag_(false), net_type_(ty), + discipline_(0), + eref_count_(0), lref_count_(0) +{ + Link::DIR dir = Link::PASSIVE; + + switch (t) { + case REG: + case IMPLICIT_REG: + dir = Link::OUTPUT; + break; + case SUPPLY0: + dir = Link::OUTPUT; + break; + case SUPPLY1: + dir = Link::OUTPUT; + break; + default: + break; + } + + initialize_dir_(dir); + + s->add_signal(this); +} + NetNet::~NetNet() { if (eref_count_ > 0) { @@ -769,19 +807,17 @@ void NetNet::set_scalar(bool flag) netenum_t*NetNet::enumeration(void) const { - return enumeration_; -} - -void NetNet::set_enumeration(netenum_t*es) -{ - ivl_assert(*this, struct_type_ == 0); - ivl_assert(*this, enumeration_ == 0); - enumeration_ = es; + return dynamic_cast (net_type_); } netstruct_t*NetNet::struct_type(void) const { - return struct_type_; + return dynamic_cast (net_type_); +} + +netdarray_t* NetNet::darray_type(void) const +{ + return dynamic_cast (net_type_); } ivl_discipline_t NetNet::get_discipline() const @@ -800,10 +836,10 @@ bool NetNet::sb_is_valid(const list&indices, long sb) const ivl_assert(*this, indices.size()+1 == packed_dims_.size()); assert(packed_dims_.size() == 1); const netrange_t&rng = packed_dims_.back(); - if (rng.msb >= rng.lsb) - return (sb <= rng.msb) && (sb >= rng.lsb); + if (rng.get_msb() >= rng.get_lsb()) + return (sb <= rng.get_msb()) && (sb >= rng.get_lsb()); else - return (sb <= rng.lsb) && (sb >= rng.msb); + return (sb <= rng.get_lsb()) && (sb >= rng.get_msb()); } long NetNet::sb_to_idx(const list&indices, long sb) const @@ -815,10 +851,10 @@ long NetNet::sb_to_idx(const list&indices, long sb) const long acc_off; long acc_wid = pcur->width(); - if (pcur->msb >= pcur->lsb) - acc_off = sb - pcur->lsb; + if (pcur->get_msb() >= pcur->get_lsb()) + acc_off = sb - pcur->get_lsb(); else - acc_off = pcur->lsb - sb; + acc_off = pcur->get_lsb() - sb; // The acc_off is the possition within the innermost // dimension. If this is a multi-dimension packed array then @@ -830,10 +866,10 @@ long NetNet::sb_to_idx(const list&indices, long sb) const -- pcur; long tmp_off; - if (pcur->msb >= pcur->lsb) - tmp_off = *icur - pcur->lsb; + if (pcur->get_msb() >= pcur->get_lsb()) + tmp_off = *icur - pcur->get_lsb(); else - tmp_off = pcur->lsb - *icur; + tmp_off = pcur->get_lsb() - *icur; acc_off += tmp_off * acc_wid; acc_wid *= pcur->width(); @@ -2053,7 +2089,7 @@ const NetNet* NetFuncDef::return_sig() const } NetSTask::NetSTask(const char*na, ivl_sfunc_as_task_t sfat, - const svector&pa) + const vector&pa) : name_(0), sfunc_as_task_(sfat), parms_(pa) { name_ = lex_strings.add(na); @@ -2062,7 +2098,7 @@ NetSTask::NetSTask(const char*na, ivl_sfunc_as_task_t sfat, NetSTask::~NetSTask() { - for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) + for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) delete parms_[idx]; /* The name_ string is perm-allocated in lex_strings. */ @@ -2080,7 +2116,7 @@ ivl_sfunc_as_task_t NetSTask::sfunc_as_task() const unsigned NetSTask::nparms() const { - return parms_.count(); + return parms_.size(); } const NetExpr* NetSTask::parm(unsigned idx) const @@ -2399,19 +2435,22 @@ long NetESignal::lsi() const { const list&packed = net_->packed_dims(); ivl_assert(*this, packed.size() == 1); - return packed.back().lsb; + return packed.back().get_lsb(); } long NetESignal::msi() const { const list&packed = net_->packed_dims(); ivl_assert(*this, packed.size() == 1); - return packed.back().msb; + return packed.back().get_msb(); } ivl_variable_type_t NetESignal::expr_type() const { - return net_->data_type(); + if (net_->darray_type()) + return IVL_VT_DARRAY; + else + return net_->data_type(); } /* diff --git a/netlist.h b/netlist.h index 7ba64280d..635e99cd0 100644 --- a/netlist.h +++ b/netlist.h @@ -76,6 +76,7 @@ class NetEvTrig; class NetEvWait; class PExpr; class PFunction; +class netdarray_t; class netenum_t; class netstruct_t; @@ -607,10 +608,12 @@ class NetNet : public NetObj, public PortType { const std::list&packed); explicit NetNet(NetScope*s, perm_string n, Type t, const std::list&packed, - const std::list&unpacked); + const std::list&unpacked, + nettype_base_t*type =0); - // This form builds a NetNet from its record definition. + // This form builds a NetNet from its record/enum definition. explicit NetNet(NetScope*s, perm_string n, Type t, netstruct_t*type); + explicit NetNet(NetScope*s, perm_string n, Type t, netdarray_t*type); virtual ~NetNet(); @@ -641,10 +644,9 @@ class NetNet : public NetObj, public PortType { bool get_scalar() const; void set_scalar(bool); - void set_enumeration(netenum_t*enum_set); netenum_t*enumeration(void) const; - netstruct_t*struct_type(void) const; + netdarray_t*darray_type(void) const; /* Attach a discipline to the net. */ ivl_discipline_t get_discipline() const; @@ -730,8 +732,7 @@ class NetNet : public NetObj, public PortType { bool isint_ : 1; // original type of integer bool is_scalar_ : 1; bool local_flag_: 1; - netenum_t*enumeration_; - netstruct_t*struct_type_; + nettype_base_t*net_type_; ivl_discipline_t discipline_; std::list packed_dims_; @@ -3190,7 +3191,7 @@ class NetSTask : public NetProc { public: NetSTask(const char*na, ivl_sfunc_as_task_t sfat, - const svector&); + const std::vector&); ~NetSTask(); const char* name() const; @@ -3208,7 +3209,7 @@ class NetSTask : public NetProc { private: const char* name_; ivl_sfunc_as_task_t sfunc_as_task_; - svectorparms_; + std::vectorparms_; }; /* @@ -3747,16 +3748,17 @@ class NetEBShift : public NetEBinary { class NetEConcat : public NetExpr { public: - NetEConcat(unsigned cnt, unsigned repeat =1); + NetEConcat(unsigned cnt, unsigned repeat, ivl_variable_type_t vt); ~NetEConcat(); // Manipulate the parameters. void set(unsigned idx, NetExpr*e); unsigned repeat() const { return repeat_; } - unsigned nparms() const { return parms_.count() ; } + unsigned nparms() const { return parms_.size() ; } NetExpr* parm(unsigned idx) const { return parms_[idx]; } + virtual ivl_variable_type_t expr_type() const; virtual NexusSet* nex_input(bool rem_out = true); virtual bool has_width() const; virtual NetEConcat* dup_expr() const; @@ -3766,8 +3768,9 @@ class NetEConcat : public NetExpr { virtual void dump(ostream&) const; private: - svectorparms_; + std::vectorparms_; unsigned repeat_; + ivl_variable_type_t expr_type_; }; diff --git a/netmisc.cc b/netmisc.cc index 8b45efaca..02bf8c52b 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -325,7 +325,7 @@ NetExpr *normalize_variable_base(NetExpr *base, { ivl_assert(*base, dims.size() == 1); const netrange_t&rng = dims.back(); - return normalize_variable_base(base, rng.msb, rng.lsb, wid, is_up); + return normalize_variable_base(base, rng.get_msb(), rng.get_lsb(), wid, is_up); } NetExpr *normalize_variable_bit_base(const list&indices, NetExpr*base, @@ -338,9 +338,9 @@ NetExpr *normalize_variable_bit_base(const list&indices, NetExpr*base, // addressing. We need that address as a slice offset to // calculate the proper complete address const netrange_t&rng = packed_dims.back(); - long slice_off = reg->sb_to_idx(indices, rng.lsb); + long slice_off = reg->sb_to_idx(indices, rng.get_lsb()); - return normalize_variable_base(base, rng.msb, rng.lsb, 1, true, slice_off); + return normalize_variable_base(base, rng.get_msb(), rng.get_lsb(), 1, true, slice_off); } NetExpr *normalize_variable_part_base(const list&indices, NetExpr*base, @@ -354,9 +354,9 @@ NetExpr *normalize_variable_part_base(const list&indices, NetExpr*base, // addressing. We need that address as a slice offset to // calculate the proper complete address const netrange_t&rng = packed_dims.back(); - long slice_off = reg->sb_to_idx(indices, rng.lsb); + long slice_off = reg->sb_to_idx(indices, rng.get_lsb()); - return normalize_variable_base(base, rng.msb, rng.lsb, wid, is_up, slice_off); + return normalize_variable_base(base, rng.get_msb(), rng.get_lsb(), wid, is_up, slice_off); } NetExpr *normalize_variable_slice_base(const list&indices, NetExpr*base, @@ -371,10 +371,10 @@ NetExpr *normalize_variable_slice_base(const list&indices, NetExpr*base, } long sb; - if (pcur->msb >= pcur->lsb) - sb = pcur->lsb; + if (pcur->get_msb() >= pcur->get_lsb()) + sb = pcur->get_lsb(); else - sb = pcur->msb; + sb = pcur->get_msb(); long loff; reg->sb_to_slice(indices, sb, loff, lwid); @@ -492,10 +492,10 @@ NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) ; cur != indices.end() ; ++cur, ++idx) { long tmp = *cur; - if (dims[idx].lsb <= dims[idx].msb) - tmp -= dims[idx].lsb; + if (dims[idx].get_lsb() <= dims[idx].get_msb()) + tmp -= dims[idx].get_lsb(); else - tmp -= dims[idx].msb; + tmp -= dims[idx].get_msb(); // Notice of this index is out of range. if (tmp < 0 || tmp >= (long)dims[idx].width()) { @@ -531,15 +531,17 @@ NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) return 0; int64_t use_base; - if (dims[idx].lsb <= dims[idx].msb) - use_base = dims[idx].lsb; + if (! dims[idx].defined()) + use_base = 0; + else if (dims[idx].get_lsb() <= dims[idx].get_msb()) + use_base = dims[idx].get_lsb(); else - use_base = dims[idx].msb; + use_base = dims[idx].get_msb(); int64_t use_stride = stride[idx]; // Account for that we are doing arithmatic and should - // have a proper width to make sure there ar no + // have a proper width to make sure there are no // losses. So calculate a min_wid width. unsigned tmp_wid; unsigned min_wid = tmp->expr_width(); diff --git a/netstruct.h b/netstruct.h index 0ffb2d55c..de0b22511 100644 --- a/netstruct.h +++ b/netstruct.h @@ -24,7 +24,7 @@ # include "ivl_target.h" # include "nettypes.h" -class netstruct_t : public LineInfo { +class netstruct_t : public LineInfo, public nettype_base_t { public: struct member_t { diff --git a/nettypes.cc b/nettypes.cc index bec698378..1bc1e71ba 100644 --- a/nettypes.cc +++ b/nettypes.cc @@ -22,16 +22,16 @@ using namespace std; +nettype_base_t::~nettype_base_t() +{ +} + unsigned long netrange_width(const list&packed) { unsigned wid = 1; for (list::const_iterator cur = packed.begin() ; cur != packed.end() ; ++cur) { - unsigned use_wid; - if (cur->msb >= cur->lsb) - use_wid = cur->msb - cur->lsb + 1; - else - use_wid = cur->lsb - cur->msb + 1; + unsigned use_wid = cur->width(); wid *= use_wid; } @@ -60,16 +60,16 @@ bool prefix_to_slice(const std::list&dims, lwid = acc_wid; -- pcur; - if (sb < pcur->msb && sb < pcur->lsb) + if (sb < pcur->get_msb() && sb < pcur->get_lsb()) return false; - if (sb > pcur->msb && sb > pcur->lsb) + if (sb > pcur->get_msb() && sb > pcur->get_lsb()) return false; long acc_off = 0; - if (pcur->msb >= pcur->lsb) - acc_off += (sb - pcur->lsb) * acc_wid; + if (pcur->get_msb() >= pcur->get_lsb()) + acc_off += (sb - pcur->get_lsb()) * acc_wid; else - acc_off += (sb - pcur->msb) * acc_wid; + acc_off += (sb - pcur->get_msb()) * acc_wid; if (prefix.size() == 0) { loff = acc_off; @@ -83,10 +83,10 @@ bool prefix_to_slice(const std::list&dims, -- pcur; -- icur; acc_wid *= pcur->width(); - if (pcur->msb >= pcur->lsb) - acc_off += (*icur - pcur->lsb) * acc_wid; + if (pcur->get_msb() >= pcur->get_lsb()) + acc_off += (*icur - pcur->get_lsb()) * acc_wid; else - acc_off += (*icur - pcur->msb) * acc_wid; + acc_off += (*icur - pcur->get_msb()) * acc_wid; } while (icur != prefix.begin()); diff --git a/nettypes.h b/nettypes.h index 6c1c5e60b..632a63e41 100644 --- a/nettypes.h +++ b/nettypes.h @@ -20,25 +20,48 @@ */ # include +# include +# include + +/* + * This is a fully abstract type that is a type that can be attached + * to a NetNet object. + */ +class nettype_base_t { + public: + virtual ~nettype_base_t() =0; +}; class netrange_t { public: - inline netrange_t() : msb(0), lsb(0) { } - inline netrange_t(long m, long l) : msb(m), lsb(l) { } - + // Create an undefined range. An undefined range is a range + // used to declare dynamic arrays, etc. + inline netrange_t() : msb_(LONG_MAX), lsb_(LONG_MAX) { } + // Create a properly defined netrange + inline netrange_t(long m, long l) : msb_(m), lsb_(l) { } + // Copy constructure. inline netrange_t(const netrange_t&that) - : msb(that.msb), lsb(that.lsb) { } + : msb_(that.msb_), lsb_(that.lsb_) { } inline netrange_t& operator = (const netrange_t&that) - { msb = that.msb; lsb = that.lsb; return *this; } + { msb_ = that.msb_; lsb_ = that.lsb_; return *this; } - public: - long msb; - long lsb; + inline bool defined() const + { return msb_!=LONG_MAX || msb_!= LONG_MAX; } inline unsigned long width()const - { if (msb >= lsb) return msb-lsb+1; else return lsb-msb+1; } + { if (!defined()) return 0; + else if (msb_ >= lsb_) return msb_-lsb_+1; + else return lsb_-msb_+1; + } + + inline long get_msb() const { assert(defined()); return msb_; } + inline long get_lsb() const { assert(defined()); return lsb_; } + + private: + long msb_; + long lsb_; }; extern unsigned long netrange_width(const std::list&dims); diff --git a/parse.y b/parse.y index 8f415d92a..032a53f37 100644 --- a/parse.y +++ b/parse.y @@ -898,8 +898,9 @@ data_type /* IEEE1800-2005: A.2.2.1 */ else $$ = $1; } | K_string - { yyerror(@1, "sorry: String data type not supported."); - $$ = 0; + { string_type_t*tmp = new string_type_t; + FILE_NAME(tmp, @1); + $$ = tmp; } ; @@ -937,12 +938,14 @@ endnew_opt : ':' K_new | ; dynamic_array_new /* IEEE1800-2005: A.2.4 */ : K_new '[' expression ']' - { yyerror(@1, "sorry: Dynamic array new expression not supported."); - $$ = 0; + { $$ = new PENew($3); + FILE_NAME($$, @1); } | K_new '[' expression ']' '(' expression ')' - { yyerror(@1, "sorry: Dynamic array new expression not supported."); - $$ = 0; + { yyerror(@1, "sorry: Dynamic array new expression with initializer not supported."); + delete $6; + $$ = new PENew($3); + FILE_NAME($$, @1); } ; @@ -1741,7 +1744,6 @@ variable_dimension /* IEEE1800-2005: A.2.5 */ | '[' ']' { list *tmp = new list; pform_range_t index (0,0); - yyerror("sorry: Dynamic array ranges not supported."); tmp->push_back(index); $$ = tmp; } diff --git a/pform.cc b/pform.cc index ee878a868..9223fe0eb 100644 --- a/pform.cc +++ b/pform.cc @@ -2829,6 +2829,11 @@ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list (data_type)) { + pform_set_string_type(string_type, names, attr); + return; + } + assert(0); } diff --git a/pform.h b/pform.h index 23d45c558..12101259a 100644 --- a/pform.h +++ b/pform.h @@ -310,6 +310,8 @@ extern void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, list< extern void pform_set_struct_type(struct_type_t*struct_type, std::list*names, std::list*attr); +extern void pform_set_string_type(string_type_t*string_type, std::list*names, std::list*attr); + /* pform_set_attrib and pform_set_type_attrib exist to support the $attribute syntax, which can only set string values to attributes. The functions keep the value strings that are diff --git a/pform_dump.cc b/pform_dump.cc index 12f2db915..47325b82a 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -233,6 +233,11 @@ void PEFNumber::dump(ostream &out) const out << value(); } +void PENew::dump(ostream&out) const +{ + out << "new [" << *size_ << "]"; +} + void PENumber::dump(ostream&out) const { out << value(); diff --git a/pform_string_type.cc b/pform_string_type.cc new file mode 100644 index 000000000..c7f626d63 --- /dev/null +++ b/pform_string_type.cc @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2012 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 + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "pform.h" +# include "parse_misc.h" +# include "ivl_assert.h" + +static void pform_set_string_type(string_type_t*string_type, perm_string name, list*attr) +{ + PWire*net = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_STRING); + pform_bind_attributes(net->attributes, attr, true); +} + +void pform_set_string_type(string_type_t*string_type, list*names, list*attr) +{ + for (list::iterator cur = names->begin() + ; cur != names->end() ; ++ cur) { + pform_set_string_type(string_type, *cur, attr); + } +} + diff --git a/pform_types.cc b/pform_types.cc index 9a85b5b7e..7650ec36e 100644 --- a/pform_types.cc +++ b/pform_types.cc @@ -23,3 +23,7 @@ data_type_t::~data_type_t() { } + +string_type_t::~string_type_t() +{ +} diff --git a/pform_types.h b/pform_types.h index cfd56e5c3..b55d31013 100644 --- a/pform_types.h +++ b/pform_types.h @@ -156,6 +156,11 @@ struct real_type_t : public data_type_t { type_t type_code; }; +struct string_type_t : public data_type_t { + inline explicit string_type_t() { } + ~string_type_t(); +}; + struct class_type_t : public data_type_t { inline explicit class_type_t(perm_string n) : name(n) { } diff --git a/sv_vpi_user.h b/sv_vpi_user.h index 606f7f73f..fadd13a08 100644 --- a/sv_vpi_user.h +++ b/sv_vpi_user.h @@ -48,7 +48,9 @@ EXTERN_C_START #define vpiIntVar 612 #define vpiByteVar 614 #define vpiLogicVar vpiReg +#define vpiStringVar 616 #define vpiBitVar 620 +#define vpiArrayVar vpiRegArray /********* TYPESPECS *************/ #define vpiEnumTypespec 633 diff --git a/t-dll-api.cc b/t-dll-api.cc index d38025c2b..8ee6ff3fb 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -2049,13 +2049,13 @@ extern "C" ivl_nexus_t ivl_scope_mod_port(ivl_scope_t net, unsigned idx) extern "C" unsigned ivl_scope_sigs(ivl_scope_t net) { assert(net); - return net->nsigs_; + return net->sigs_.size(); } extern "C" ivl_signal_t ivl_scope_sig(ivl_scope_t net, unsigned idx) { assert(net); - assert(idx < net->nsigs_); + assert(idx < net->sigs_.size()); return net->sigs_[idx]; } @@ -2196,13 +2196,13 @@ extern "C" unsigned ivl_signal_packed_dimensions(ivl_signal_t net) extern "C" int ivl_signal_packed_msb(ivl_signal_t net, unsigned dim) { assert(dim < net->packed_dims.size()); - return net->packed_dims[dim].msb; + return net->packed_dims[dim].get_msb(); } extern "C" int ivl_signal_packed_lsb(ivl_signal_t net, unsigned dim) { assert(dim < net->packed_dims.size()); - return net->packed_dims[dim].lsb; + return net->packed_dims[dim].get_lsb(); } extern "C" int ivl_signal_msb(ivl_signal_t net) @@ -2211,7 +2211,7 @@ extern "C" int ivl_signal_msb(ivl_signal_t net) return 0; assert(net->packed_dims.size() == 1); - return net->packed_dims[0].msb; + return net->packed_dims[0].get_msb(); } extern "C" int ivl_signal_lsb(ivl_signal_t net) @@ -2220,7 +2220,7 @@ extern "C" int ivl_signal_lsb(ivl_signal_t net) return 0; assert(net->packed_dims.size() == 1); - return net->packed_dims[0].lsb; + return net->packed_dims[0].get_lsb(); } extern "C" ivl_scope_t ivl_signal_scope(ivl_signal_t net) diff --git a/t-dll-expr.cc b/t-dll-expr.cc index 0db2ffd62..13748ad08 100644 --- a/t-dll-expr.cc +++ b/t-dll-expr.cc @@ -200,7 +200,7 @@ void dll_target::expr_concat(const NetEConcat*net) assert(cur); cur->type_ = IVL_EX_CONCAT; - cur->value_ = IVL_VT_VECTOR; + cur->value_ = net->expr_type(); cur->width_ = net->expr_width(); cur->signed_ = net->has_sign() ? 1 : 0; cur->sized_ = 1; diff --git a/t-dll.cc b/t-dll.cc index 3960681fe..c1a376c41 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -257,7 +257,7 @@ ivl_signal_t dll_target::find_signal(ivl_design_s &des, const NetNet*net) perm_string nname = net->name(); - for (unsigned idx = 0 ; idx < scope->nsigs_ ; idx += 1) { + for (unsigned idx = 0 ; idx < scope->sigs_.size() ; idx += 1) { if (strcmp(scope->sigs_[idx]->name_, nname) == 0) return scope->sigs_[idx]; } @@ -533,8 +533,6 @@ void dll_target::add_root(ivl_design_s &des__, const NetScope *s) root_->name_ = name; FILE_NAME(root_, s); root_->parent = 0; - root_->nsigs_ = 0; - root_->sigs_ = 0; root_->nlog_ = 0; root_->log_ = 0; root_->nevent_ = 0; @@ -2280,8 +2278,6 @@ void dll_target::scope(const NetScope*net) scop->parent = find_scope(des_, net->parent()); assert(scop->parent); scop->parent->children[net->fullname()] = scop; - scop->nsigs_ = 0; - scop->sigs_ = 0; scop->nlog_ = 0; scop->log_ = 0; scop->nevent_ = 0; @@ -2371,20 +2367,7 @@ void dll_target::signal(const NetNet*net) assert(obj->scope_); FILE_NAME(obj, net); - if (obj->scope_->nsigs_ == 0) { - assert(obj->scope_->sigs_ == 0); - obj->scope_->nsigs_ = 1; - obj->scope_->sigs_ = (ivl_signal_t*)malloc(sizeof(ivl_signal_t)); - - } else { - assert(obj->scope_->sigs_); - obj->scope_->nsigs_ += 1; - obj->scope_->sigs_ = (ivl_signal_t*) - realloc(obj->scope_->sigs_, - obj->scope_->nsigs_*sizeof(ivl_signal_t)); - } - - obj->scope_->sigs_[obj->scope_->nsigs_-1] = obj; + obj->scope_->sigs_.push_back(obj); /* Save the primitive properties of the signal in the @@ -2490,6 +2473,10 @@ void dll_target::signal(const NetNet*net) obj->nattr = net->attr_cnt(); obj->attr = fill_in_attributes(net); + /* If this is a dynamic array, then set the type to DARRAY. */ + if (net->darray_type()) { + obj->data_type = IVL_VT_DARRAY; + } /* Get the nexus objects for all the pins of the signal. If the signal has only one pin, then write the single @@ -2502,11 +2489,11 @@ void dll_target::signal(const NetNet*net) if (obj->array_dimensions_ == 1) { const vector& dims = net->unpacked_dims(); - if (dims[0].msb < dims[0].lsb) { - obj->array_base = dims[0].msb; + if (dims[0].get_msb() < dims[0].get_lsb()) { + obj->array_base = dims[0].get_msb(); obj->array_addr_swapped = false; } else { - obj->array_base = dims[0].lsb; + obj->array_base = dims[0].get_lsb(); obj->array_addr_swapped = true; } obj->array_words = net->unpacked_count(); diff --git a/t-dll.h b/t-dll.h index ca5f4db3c..cc617bb59 100644 --- a/t-dll.h +++ b/t-dll.h @@ -627,8 +627,7 @@ struct ivl_scope_s { std::vector enumerations_; - unsigned nsigs_; - ivl_signal_t*sigs_; + std::vector sigs_; unsigned nlog_; ivl_net_logic_t*log_; diff --git a/tgt-stub/expression.c b/tgt-stub/expression.c index 79420225b..5972827a5 100644 --- a/tgt-stub/expression.c +++ b/tgt-stub/expression.c @@ -165,6 +165,42 @@ static void show_memory_expression(ivl_expr_t net, unsigned ind) width); } +static void show_select_expression(ivl_expr_t net, unsigned ind) +{ + unsigned width = ivl_expr_width(net); + const char*sign = ivl_expr_signed(net)? "signed" : "unsigned"; + ivl_expr_t oper1 = ivl_expr_oper1(net); + ivl_expr_t oper2 = ivl_expr_oper2(net); + + if (ivl_expr_value(oper1) == IVL_VT_STRING) { + /* If the sub-expression is a STRING, then this is a + substring and the code generator will handle it + differently. */ + fprintf(out, "%*s\n", ind, "", width, width/8); + if (width%8 != 0) + fprintf(out, "%*sERROR: Width should be a multiple of 8 bits.\n", ind, ""); + show_expression(oper1, ind+3); + show_expression(oper2, ind+3); + + } else if (oper2) { + /* If oper2 is present, then it is the base of a part + select. The width of the expression defines the range + of the part select. */ + fprintf(out, "%*s\n", ind, "", + width, sign); + show_expression(oper1, ind+3); + show_expression(oper2, ind+3); + + } else { + /* There is no base expression so this is a pad + operation. The sub-expression is padded (signed or + unsigned as appropriate) to the expression width. */ + fprintf(out, "%*s\n", ind, "", + width, sign); + show_expression(oper1, ind+3); + } +} + static void show_signal_expression(ivl_expr_t net, unsigned ind) { unsigned width = ivl_expr_width(net); @@ -173,6 +209,7 @@ static void show_signal_expression(ivl_expr_t net, unsigned ind) ivl_expr_t word = ivl_expr_oper1(net); ivl_signal_t sig = ivl_expr_signal(net); + const char*vt_sig = data_type_string(ivl_signal_data_type(sig)); unsigned dimensions = ivl_signal_dimensions(sig); unsigned word_count = ivl_signal_array_count(sig); @@ -182,8 +219,8 @@ static void show_signal_expression(ivl_expr_t net, unsigned ind) stub_errors += 1; } - fprintf(out, "%*s\n", ind, "", - ivl_expr_name(net), word_count, width, sign, vt); + fprintf(out, "%*s\n", ind, "", + ivl_expr_name(net), word_count, width, sign, vt, vt_sig); /* If the expression refers to a signal array, then there must also be a word select expression, and if the signal is not an @@ -312,18 +349,7 @@ void show_expression(ivl_expr_t net, unsigned ind) } case IVL_EX_SELECT: - /* The SELECT expression can be used to express part - select, or if the base is null vector extension. */ - if (ivl_expr_oper2(net)) { - fprintf(out, "%*s\n", ind, "", - width, sign); - show_expression(ivl_expr_oper1(net), ind+3); - show_expression(ivl_expr_oper2(net), ind+3); - } else { - fprintf(out, "%*s\n", ind, "", - width, sign); - show_expression(ivl_expr_oper1(net), ind+3); - } + show_select_expression(net, ind); break; case IVL_EX_STRING: diff --git a/tgt-stub/statement.c b/tgt-stub/statement.c index 1b89e43ec..1bfa6318a 100644 --- a/tgt-stub/statement.c +++ b/tgt-stub/statement.c @@ -21,10 +21,36 @@ # include "priv.h" # include +/* + * If the l-value signal is a darray object, then the ivl_lval_mux() + * gets you the array index expression. + */ +static unsigned show_assign_lval_darray(ivl_lval_t lval, unsigned ind) +{ + ivl_signal_t sig = ivl_lval_sig(lval); + assert(sig); + + if (ivl_lval_idx(lval)) { + fprintf(out, "%*sAddress-0 select of dynamic array:\n", ind+4, ""); + show_expression(ivl_lval_idx(lval), ind+6); + } + + if (ivl_lval_mux(lval)) { + fprintf(out, "%*sERROR: unexpected ivl_lval_mux() expression:\n", ind+4, ""); + stub_errors += 1; + show_expression(ivl_lval_mux(lval), ind+6); + } + if (ivl_lval_part_off(lval)) { + fprintf(out, "%*sERROR: unexpected Part select expression:\n", ind+4, ""); + stub_errors += 1; + show_expression(ivl_lval_part_off(lval), ind+8); + } + + return ivl_lval_width(lval); +} + static unsigned show_assign_lval(ivl_lval_t lval, unsigned ind) { - unsigned wid = 0; - ivl_signal_t sig = ivl_lval_sig(lval); assert(sig); @@ -34,6 +60,10 @@ static unsigned show_assign_lval(ivl_lval_t lval, unsigned ind) ivl_signal_width(sig), ivl_lval_width(lval)); + /* Special case: target signal is a darray. */ + if (ivl_signal_data_type(sig) == IVL_VT_DARRAY) + return show_assign_lval_darray(lval, ind); + if (ivl_lval_idx(lval)) { fprintf(out, "%*sAddress-0 select expression:\n", ind+4, ""); show_expression(ivl_lval_idx(lval), ind+6); @@ -59,9 +89,7 @@ static unsigned show_assign_lval(ivl_lval_t lval, unsigned ind) show_expression(ivl_lval_part_off(lval), ind+8); } - wid = ivl_lval_width(lval); - - return wid; + return ivl_lval_width(lval); } static void show_stmt_cassign(ivl_statement_t net, unsigned ind) diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index 3cddd2ab6..882d7a46b 100644 --- a/tgt-stub/stub.c +++ b/tgt-stub/stub.c @@ -169,6 +169,9 @@ const char*data_type_string(ivl_variable_type_t vtype) case IVL_VT_STRING: vt = "string"; break; + case IVL_VT_DARRAY: + vt = "darray"; + break; } return vt; @@ -1260,22 +1263,29 @@ static void show_signal(ivl_signal_t net) break; } + data_type = "?data?"; switch (ivl_signal_data_type(net)) { + case IVL_VT_NO_TYPE: + data_type = ""; + break; case IVL_VT_BOOL: data_type = "bool"; break; - case IVL_VT_LOGIC: data_type = "logic"; break; - case IVL_VT_REAL: data_type = "real"; break; - - default: - data_type = "?data?"; + case IVL_VT_STRING: + data_type = "string"; + break; + case IVL_VT_DARRAY: + data_type = "darray"; + break; + case IVL_VT_VOID: + data_type = "void"; break; } @@ -1358,6 +1368,15 @@ static void show_signal(ivl_signal_t net) } } + switch (ivl_signal_data_type(net)) { + case IVL_VT_NO_TYPE: + case IVL_VT_VOID: + fprintf(out, " ERROR: Invalid type for signal: %s\n", data_type); + stub_errors += 1; + break; + default: + break; + } } void test_expr_is_delay(ivl_expr_t expr) diff --git a/tgt-vvp/Makefile.in b/tgt-vvp/Makefile.in index 9edeb32ec..8762e9071 100644 --- a/tgt-vvp/Makefile.in +++ b/tgt-vvp/Makefile.in @@ -49,7 +49,8 @@ CFLAGS = @WARNING_FLAGS@ @CFLAGS@ LDFLAGS = @LDFLAGS@ O = vvp.o draw_enum.o draw_mux.o draw_net_input.o draw_switch.o draw_ufunc.o draw_vpi.o \ - eval_bool.o eval_expr.o eval_real.o modpath.o stmt_assign.o vector.o \ + eval_bool.o eval_expr.o eval_object.o eval_real.o eval_string.o \ + modpath.o stmt_assign.o vector.o \ vvp_process.o vvp_scope.o all: dep vvp.tgt vvp.conf vvp-s.conf diff --git a/tgt-vvp/draw_vpi.c b/tgt-vvp/draw_vpi.c index ef4bf50c0..d7bb7317d 100644 --- a/tgt-vvp/draw_vpi.c +++ b/tgt-vvp/draw_vpi.c @@ -31,6 +31,9 @@ struct args_info { char*text; int vec_flag; /* True if the vec must be released. */ struct vector_info vec; + /* String Stack position if this argument is a calculated string. */ + int str_flag; + unsigned str_stack; struct args_info *child; /* Arguments can be nested. */ }; @@ -178,6 +181,18 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result, if (ivl_expr_type(vexpr) != IVL_EX_SIGNAL && ivl_expr_type(vexpr) != IVL_EX_SELECT) return 0; + /* If the expression is a substring expression, then + the xPV method of passing the argument will not work + and we have to resort to the default method. */ + if (ivl_expr_value(vexpr) == IVL_VT_STRING) + return 0; + + /* If the sub-expression is a DARRAY, then this select + is a dynamic-array word select. Handle that + elsewhere. */ + if (ivl_expr_value(vexpr) == IVL_VT_DARRAY) + return 0; + /* The signal is part of an array. */ /* Add &APV<> code here when it is finished. */ bexpr = ivl_expr_oper2(expr); @@ -265,6 +280,11 @@ static void draw_vpi_taskfunc_args(const char*call_string, ivl_parameter_t par; + /* Keep track of how much string stack this function call is + going to need. We'll need this for making stack references, + and also to clean out the stack when done. */ + unsigned str_stack_need = 0; + /* Figure out how many expressions are going to be evaluated for this task call. I won't need to evaluate expressions for items that are VPI objects directly. */ @@ -376,7 +396,17 @@ static void draw_vpi_taskfunc_args(const char*call_string, "W<%u,r>", args[idx].vec.base); break; case IVL_VT_STRING: - /* STRING expressions not supported yet. */ + /* Eval the string into the stack, and tell VPI + about the stack position. */ + draw_eval_string(expr); + args[idx].vec_flag = 0; + args[idx].vec.base = 0; + args[idx].vec.wid = 0; + args[idx].str_flag = 1; + args[idx].str_stack = str_stack_need; + str_stack_need += 1; + buffer[0] = 0; + break; default: assert(0); } @@ -388,7 +418,16 @@ static void draw_vpi_taskfunc_args(const char*call_string, for (idx = 0 ; idx < parm_count ; idx += 1) { struct args_info*ptr; - fprintf(vvp_out, ", %s", args[idx].text); + if (args[idx].str_flag) { + /* If this is a string stack reference, then + calculate the stack depth and use that to + generate the completed string. */ + unsigned pos = str_stack_need - args[idx].str_stack - 1; + fprintf(vvp_out, ", S<%u,str>",pos); + } else { + fprintf(vvp_out, ", %s", args[idx].text); + } + free(args[idx].text); /* Clear the nested children vectors. */ for (ptr = &args[idx]; ptr != NULL; ptr = ptr->child) { @@ -409,6 +448,9 @@ static void draw_vpi_taskfunc_args(const char*call_string, free(args); fprintf(vvp_out, ";\n"); + + if (str_stack_need > 0) + fprintf(vvp_out, " %%pop/str %u;\n", str_stack_need); } void draw_vpi_task_call(ivl_statement_t tnet) diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 3e7b548d0..47b997c08 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -459,6 +459,39 @@ static struct vector_info draw_binary_expr_eq_real(ivl_expr_t expr) return res; } +static struct vector_info draw_binary_expr_eq_string(ivl_expr_t expr) +{ + ivl_expr_t le = ivl_expr_oper1(expr); + ivl_expr_t re = ivl_expr_oper2(expr); + + struct vector_info res; + res.base = allocate_vector(1); + res.wid = 1; + assert(res.base); + + draw_eval_string(le); + draw_eval_string(re); + + fprintf(vvp_out, " %%cmp/str;\n"); + + switch (ivl_expr_opcode(expr)) { + + case 'e': /* == */ + fprintf(vvp_out, " %%mov %u, 4, 1;\n", res.base); + break; + + case 'n': /* != */ + fprintf(vvp_out, " %%mov %u, 4, 1;\n", res.base); + fprintf(vvp_out, " %%inv %u, 1;\n", res.base); + break; + + default: + assert(0); + } + + return res; +} + static struct vector_info draw_binary_expr_eq(ivl_expr_t expr, unsigned ewid, int stuff_ok_flag) @@ -476,13 +509,30 @@ static struct vector_info draw_binary_expr_eq(ivl_expr_t expr, return draw_binary_expr_eq_real(expr); } + if ((ivl_expr_value(le) == IVL_VT_STRING) + && (ivl_expr_value(re) == IVL_VT_STRING)) { + return draw_binary_expr_eq_string(expr); + } + + if ((ivl_expr_value(le) == IVL_VT_STRING) + && (ivl_expr_type(re) == IVL_EX_STRING)) { + return draw_binary_expr_eq_string(expr); + } + + if ((ivl_expr_type(le) == IVL_EX_STRING) + && (ivl_expr_value(re) == IVL_VT_STRING)) { + return draw_binary_expr_eq_string(expr); + } + if (number_is_immediate(re,16,0) && !number_is_unknown(re)) return draw_eq_immediate(expr, ewid, le, re, stuff_ok_flag); assert(ivl_expr_value(le) == IVL_VT_LOGIC - || ivl_expr_value(le) == IVL_VT_BOOL); + || ivl_expr_value(le) == IVL_VT_BOOL + || ivl_expr_value(le) == IVL_VT_STRING); assert(ivl_expr_value(re) == IVL_VT_LOGIC - || ivl_expr_value(re) == IVL_VT_BOOL); + || ivl_expr_value(re) == IVL_VT_BOOL + || ivl_expr_value(re) == IVL_VT_STRING); wid = ivl_expr_width(le); if (ivl_expr_width(re) > wid) @@ -825,6 +875,57 @@ static struct vector_info draw_binary_expr_le_real(ivl_expr_t expr) return res; } +static struct vector_info draw_binary_expr_le_string(ivl_expr_t expr) +{ + struct vector_info res; + + ivl_expr_t le = ivl_expr_oper1(expr); + ivl_expr_t re = ivl_expr_oper2(expr); + + res.base = allocate_vector(1); + res.wid = 1; + + assert(res.base); + + /* The %cmp/str function implements < and <= operands. To get + the > and >= results, simply switch the order of the + operands. */ + switch (ivl_expr_opcode(expr)) { + case '<': + case 'L': + draw_eval_string(le); + draw_eval_string(re); + break; + case '>': + case 'G': + draw_eval_string(re); + draw_eval_string(le); + break; + default: + assert(0); + } + + switch (ivl_expr_opcode(expr)) { + case '<': + case '>': + fprintf(vvp_out, " %%cmp/str;\n"); + fprintf(vvp_out, " %%mov %u, 5, 1;\n", res.base); + break; + + case 'L': /* <= */ + case 'G': /* >= */ + fprintf(vvp_out, " %%cmp/str;\n"); + fprintf(vvp_out, " %%or 5, 4, 1;\n"); + fprintf(vvp_out, " %%mov %u, 5, 1;\n", res.base); + break; + + default: + assert(0); + } + + return res; +} + static struct vector_info draw_binary_expr_le_bool(ivl_expr_t expr, unsigned wid) { @@ -919,6 +1020,21 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t expr, return draw_binary_expr_le_bool(expr, wid); } + if ((ivl_expr_value(le) == IVL_VT_STRING) + && (ivl_expr_value(re) == IVL_VT_STRING)) { + return draw_binary_expr_le_string(expr); + } + + if ((ivl_expr_value(le) == IVL_VT_STRING) + && (ivl_expr_type(re) == IVL_EX_STRING)) { + return draw_binary_expr_le_string(expr); + } + + if ((ivl_expr_type(le) == IVL_EX_STRING) + && (ivl_expr_value(re) == IVL_VT_STRING)) { + return draw_binary_expr_eq_string(expr); + } + assert(ivl_expr_value(le) == IVL_VT_LOGIC || ivl_expr_value(le) == IVL_VT_BOOL); assert(ivl_expr_value(re) == IVL_VT_LOGIC @@ -2646,6 +2762,25 @@ static struct vector_info draw_select_unsized_literal(ivl_expr_t expr, return res; } +static void draw_select_string_dest(ivl_expr_t expr, struct vector_info res) +{ + ivl_expr_t sube = ivl_expr_oper1(expr); + ivl_expr_t shift = ivl_expr_oper2(expr); + int shift_i; + + draw_eval_string(sube); + + shift_i = allocate_word(); + draw_eval_expr_into_integer(shift, shift_i); + + assert(res.wid % 8 == 0); + + clr_word(shift_i); + + fprintf(vvp_out, " %%substr/v %u, %d, %u;\n", res.base, shift_i, res.wid); + fprintf(vvp_out, " %%pop/str 1;\n"); +} + static struct vector_info draw_select_expr(ivl_expr_t expr, unsigned wid, int stuff_ok_flag) { @@ -2668,6 +2803,28 @@ static struct vector_info draw_select_expr(ivl_expr_t expr, unsigned wid, return res; } + /* Special case: The sub expression is a string, so do a + string select then a part select from that. */ + if (ivl_expr_value(sube) == IVL_VT_STRING) { + res.base = allocate_vector(wid); + res.wid = wid; + draw_select_string_dest(expr, res); + return res; + } + + /* Special case: The sub-expression is a DARRAY variable, so + do a dynamic array word load. */ + if (ivl_expr_value(sube) == IVL_VT_DARRAY) { + ivl_signal_t sig = ivl_expr_signal(sube); + assert(sig); + res.base = allocate_vector(wid); + res.wid = wid; + draw_eval_expr_into_integer(shift, 3); + fprintf(vvp_out, " %%load/dar %u, v%p_0, %u;\n", + res.base, sig, res.wid); + return res; + } + if (ivl_expr_type(sube) == IVL_EX_SIGNAL) { res = draw_select_signal(expr, sube, shift, ivl_expr_width(expr), wid); @@ -2770,6 +2927,13 @@ static void draw_select_expr_dest(ivl_expr_t expr, struct vector_info dest, ivl_expr_t sube = ivl_expr_oper1(expr); ivl_expr_t shift= ivl_expr_oper2(expr); + /* Special case: The sub expression is a string, so do a + string select then a part select from that. */ + if (ivl_expr_value(sube) == IVL_VT_STRING) { + draw_select_string_dest(expr, dest); + return; + } + /* If the shift expression is not present, then this is really a pad expression, and that can be handled pretty easily. Evaluate the subexpression into the destination, @@ -2897,7 +3061,6 @@ static struct vector_info draw_sfunc_expr(ivl_expr_t expr, unsigned wid) unsigned parm_count = ivl_expr_parms(expr); struct vector_info res; - /* If the function has no parameters, then use this short-form to draw the statement. */ if (parm_count == 0) { diff --git a/tgt-vvp/eval_object.c b/tgt-vvp/eval_object.c new file mode 100644 index 000000000..ae72f8686 --- /dev/null +++ b/tgt-vvp/eval_object.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2012 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 + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "vvp_priv.h" +# include +# include + +static int eval_darray_new(ivl_expr_t ex) +{ + unsigned size_reg = allocate_word(); + ivl_expr_t size_expr = ivl_expr_parm(ex, 0); + draw_eval_expr_into_integer(size_expr, size_reg); + clr_word(size_reg); + + // XXXX: Assume elements are 32bit integers. + fprintf(vvp_out, " %%new/darray %u, \"sb32\";\n", size_reg); + + return 0; +} + +static int draw_eval_object_sfunc(ivl_expr_t ex) +{ + const char*name = ivl_expr_name(ex); + + if (strcmp(name, "$ivl_darray_method$new") == 0) + return eval_darray_new(ex); + + fprintf(vvp_out, "; ERROR: Invalid system function %s for darray\n", name); + return 1; +} + +int draw_eval_object(ivl_expr_t ex) +{ + switch (ivl_expr_type(ex)) { + case IVL_EX_SFUNC: + return draw_eval_object_sfunc(ex); + + default: + fprintf(vvp_out, "; ERROR: Invalid expression type %u\n", ivl_expr_type(ex)); + return 1; + + } +} diff --git a/tgt-vvp/eval_string.c b/tgt-vvp/eval_string.c new file mode 100644 index 000000000..bc4a477b9 --- /dev/null +++ b/tgt-vvp/eval_string.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2012 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 + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "vvp_priv.h" +# include + +static void fallback_eval(ivl_expr_t expr) +{ + struct vector_info res = draw_eval_expr(expr, 0); + fprintf(vvp_out, " %%pushv/str %u, %u; Cast BOOL/LOGIC to string\n", + res.base, res.wid); + if (res.base > 0) + clr_vector(res); +} + +static void string_ex_concat(ivl_expr_t expr) +{ + unsigned repeat; + + assert(ivl_expr_parms(expr) != 0); + assert(ivl_expr_repeat(expr) != 0); + + /* Push the first string onto the stack, no matter what. */ + draw_eval_string(ivl_expr_parm(expr,0)); + + for (repeat = 0 ; repeat < ivl_expr_repeat(expr) ; repeat += 1) { + unsigned idx; + for (idx = (repeat==0)? 1 : 0 ; idx < ivl_expr_parms(expr) ; idx += 1) { + ivl_expr_t sub = ivl_expr_parm(expr,idx); + + /* Special case: If operand is a string literal, + then concat it using the %concati/str + instruction. */ + if (ivl_expr_type(sub) == IVL_EX_STRING) { + fprintf(vvp_out, " %%concati/str \"%s\";\n", + ivl_expr_string(sub)); + continue; + } + + draw_eval_string(sub); + fprintf(vvp_out, " %%concat/str;\n"); + } + } +} + +static void string_ex_signal(ivl_expr_t expr) +{ + ivl_signal_t sig = ivl_expr_signal(expr); + + if (ivl_signal_data_type(sig) == IVL_VT_STRING) { + fprintf(vvp_out, " %%load/str v%p_0;\n", sig); + return; + } + + fallback_eval(expr); +} + +void draw_eval_string(ivl_expr_t expr) +{ + + switch (ivl_expr_type(expr)) { + case IVL_EX_STRING: + fprintf(vvp_out, " %%pushi/str \"%s\";\n", ivl_expr_string(expr)); + break; + + case IVL_EX_SIGNAL: + string_ex_signal(expr); + break; + + case IVL_EX_CONCAT: + string_ex_concat(expr); + break; + + default: + fallback_eval(expr); + break; + } +} diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index 13f2e2391..22e117687 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -731,6 +731,74 @@ static int show_stmt_assign_sig_real(ivl_statement_t net) return 0; } +static int show_stmt_assign_sig_string(ivl_statement_t net) +{ + ivl_lval_t lval = ivl_stmt_lval(net, 0); + ivl_expr_t rval = ivl_stmt_rval(net); + ivl_expr_t part = ivl_lval_part_off(lval); + ivl_signal_t var= ivl_lval_sig(lval); + + assert(ivl_stmt_lvals(net) == 1); + assert(ivl_stmt_opcode(net) == 0); + assert(ivl_lval_mux(lval) == 0); + + /* Simplest case: no mux. Evaluate the r-value as a string and + store the result into the variable. Note that the + %store/str opcode pops the string result. */ + if (part == 0) { + draw_eval_string(rval); + fprintf(vvp_out, " %%store/str v%p_0;\n", var); + return 0; + } + + /* Calculate the character select for the word. */ + int mux_word = allocate_word(); + draw_eval_expr_into_integer(part, mux_word); + + /* Evaluate the r-value as a vector. */ + struct vector_info rvec = draw_eval_expr_wid(rval, 8, STUFF_OK_XZ); + + assert(rvec.wid == 8); + fprintf(vvp_out, " %%putc/str/v v%p_0, %d, %u;\n", var, mux_word, rvec.base); + + clr_vector(rvec); + clr_word(mux_word); + return 0; +} + +static int show_stmt_assign_sig_darray(ivl_statement_t net) +{ + int errors = 0; + ivl_lval_t lval = ivl_stmt_lval(net, 0); + ivl_expr_t rval = ivl_stmt_rval(net); + ivl_expr_t part = ivl_lval_part_off(lval); + ivl_signal_t var= ivl_lval_sig(lval); + ivl_expr_t mux = ivl_lval_idx(lval); + + assert(ivl_stmt_lvals(net) == 1); + assert(ivl_stmt_opcode(net) == 0); + assert(ivl_lval_mux(lval) == 0); + assert(part == 0); + + if (mux) { + struct vector_info rvec = draw_eval_expr_wid(rval, ivl_lval_width(lval), + STUFF_OK_XZ); + /* The %set/dar expects the array index to be in index + register 3. Calculate the index in place. */ + draw_eval_expr_into_integer(mux, 3); + + fprintf(vvp_out, " %%set/dar v%p_0, %u, %u;\n", + var, rvec.base, rvec.wid); + + if (rvec.base >= 4) clr_vector(rvec); + + } else { + errors += draw_eval_object(rval); + fprintf(vvp_out, " %%store/obj v%p_0;\n", var); + } + + return errors; +} int show_stmt_assign(ivl_statement_t net) { @@ -746,5 +814,13 @@ int show_stmt_assign(ivl_statement_t net) return show_stmt_assign_sig_real(net); } + if (sig && (ivl_signal_data_type(sig) == IVL_VT_STRING)) { + return show_stmt_assign_sig_string(net); + } + + if (sig && (ivl_signal_data_type(sig) == IVL_VT_DARRAY)) { + return show_stmt_assign_sig_darray(net); + } + return show_stmt_assign_vector(net); } diff --git a/tgt-vvp/vvp_priv.h b/tgt-vvp/vvp_priv.h index 64fb94571..544936895 100644 --- a/tgt-vvp/vvp_priv.h +++ b/tgt-vvp/vvp_priv.h @@ -313,6 +313,18 @@ extern int draw_eval_real(ivl_expr_t ex); */ extern int draw_eval_bool64(ivl_expr_t ex); +/* + * The draw_eval_string functio evaluates the expression as a string, + * and pushes the string onto the string stack. + */ +extern void draw_eval_string(ivl_expr_t ex); + +/* + * The draw_eval_string functio evaluates the expression as an object, + * and pushes the object onto the object stack. + */ +extern int draw_eval_object(ivl_expr_t ex); + extern int show_stmt_assign(ivl_statement_t net); extern void show_stmt_file_line(ivl_statement_t net, const char*desc); diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index c30fab792..702d14ef9 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -1646,8 +1646,29 @@ static int show_stmt_while(ivl_statement_t net, ivl_scope_t sscope) return rc; } +static int show_delete_method(ivl_statement_t net) +{ + show_stmt_file_line(net, "Delete object"); + + unsigned parm_count = ivl_stmt_parm_count(net); + if (parm_count < 1) + return 1; + + ivl_expr_t parm = ivl_stmt_parm(net, 0); + assert(ivl_expr_type(parm) == IVL_EX_SIGNAL); + ivl_signal_t var = ivl_expr_signal(parm); + + fprintf(vvp_out, " %%delete/obj v%p_0;\n", var); + return 0; +} + static int show_system_task_call(ivl_statement_t net) { + const char*stmt_name = ivl_stmt_name(net); + + if (strcmp(stmt_name,"$ivl_darray_method$delete") == 0) + return show_delete_method(net); + show_stmt_file_line(net, "System task call."); draw_vpi_task_call(net); diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index c927ed932..d87b13bd6 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -502,6 +502,16 @@ static void draw_reg_in_scope(ivl_signal_t sig) vvp_mangle_name(ivl_signal_basename(sig)), swapped ? first: last, swapped ? last : first, msb, lsb); + } else if (ivl_signal_data_type(sig) == IVL_VT_DARRAY) { + fprintf(vvp_out, "v%p_0 .var/darray \"%s\";%s\n", sig, + vvp_mangle_name(ivl_signal_basename(sig)), + ivl_signal_local(sig)? " Local signal" : ""); + + } else if (ivl_signal_data_type(sig) == IVL_VT_STRING) { + fprintf(vvp_out, "v%p_0 .var/str \"%s\";%s\n", sig, + vvp_mangle_name(ivl_signal_basename(sig)), + ivl_signal_local(sig)? " Local signal" : ""); + } else { fprintf(vvp_out, "v%p_0 .var%s %s\"%s\", %d %d;%s\n", diff --git a/vpi/Makefile.in b/vpi/Makefile.in index fbe12f2c4..ceb58603c 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -52,10 +52,10 @@ CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@ LDFLAGS = @LDFLAGS@ # Object files for system.vpi -O = sys_table.o sys_convert.o sys_countdrivers.o sys_deposit.o sys_display.o \ +O = sys_table.o sys_convert.o sys_countdrivers.o sys_darray.o sys_deposit.o sys_display.o \ sys_fileio.o sys_finish.o sys_icarus.o sys_plusargs.o sys_queue.o \ sys_random.o sys_random_mti.o sys_readmem.o sys_readmem_lex.o sys_scanf.o \ - sys_sdf.o sys_time.o sys_vcd.o sys_vcdoff.o vcd_priv.o mt19937int.o \ + sys_sdf.o sys_string.o sys_time.o sys_vcd.o sys_vcdoff.o vcd_priv.o mt19937int.o \ sys_priv.o sdf_lexor.o sdf_parse.o stringheap.o vams_simparam.o \ table_mod.o table_mod_lexor.o table_mod_parse.o OPP = vcd_priv2.o diff --git a/vpi/sys_darray.c b/vpi/sys_darray.c new file mode 100644 index 000000000..857464a66 --- /dev/null +++ b/vpi/sys_darray.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2012 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 + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +# include "sys_priv.h" +# include + +static PLI_INT32 one_darray_arg_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv; + vpiHandle arg; + + argv = vpi_iterate(vpiArgument, callh); + if (argv == 0) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s requires a string argument.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + + arg = vpi_scan(argv); + if (arg == 0) return 0; + + 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 has too many arguments.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + + return 0; +} + +static PLI_INT32 size_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv; + vpiHandle arg; + + argv = vpi_iterate(vpiArgument, callh); + assert(argv); + arg = vpi_scan(argv); + assert(arg); + vpi_free_object(argv); + + int res = vpi_get(vpiSize, arg); + + s_vpi_value value; + value.format = vpiIntVal; + value.value.integer = res; + + vpi_put_value(callh, &value, 0, vpiNoDelay); + + return 0; +} + +void sys_darray_register(void) +{ + s_vpi_systf_data tf_data; + vpiHandle res; + + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiIntFunc; + tf_data.tfname = "$ivl_darray_method$size"; + tf_data.calltf = size_calltf; + tf_data.compiletf = one_darray_arg_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$ivl_darray_method$size"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); +} diff --git a/vpi/sys_display.c b/vpi/sys_display.c index d5fdb4234..6d92268f3 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -964,6 +964,18 @@ static char *get_display(unsigned int *rtnsz, const struct strobe_cb_info *info) memcpy(rtn+size-1, buf, width); break; + /* Process string variables like string constants: interpret + the contained strings like format strings. */ + case vpiStringVar: + value.format = vpiStringVal; + vpi_get_value(item, &value); + fmt = strdup(value.value.str); + width = get_format(&result, fmt, info, &idx); + free(fmt); + rtn = realloc(rtn, (size+width)*sizeof(char)); + memcpy(rtn+size-1, result, width); + break; + case vpiSysFuncCall: func_name = vpi_get_str(vpiName, item); if (strcmp(func_name, "$time") == 0) { @@ -1071,6 +1083,7 @@ static int sys_check_args(vpiHandle callh, vpiHandle argv, const PLI_BYTE8*name, case vpiLongIntVar: case vpiTimeVar: case vpiRealVar: + case vpiStringVar: case vpiSysFuncCall: break; diff --git a/vpi/sys_string.c b/vpi/sys_string.c new file mode 100644 index 000000000..faff55cc9 --- /dev/null +++ b/vpi/sys_string.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2012 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 + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "sys_priv.h" +# include + +static PLI_INT32 one_string_arg_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv; + vpiHandle arg; + + argv = vpi_iterate(vpiArgument, callh); + if (argv == 0) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s requires a string argument.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + + arg = vpi_scan(argv); + if (arg == 0) return 0; + + 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 has too many arguments.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + + return 0; +} + +static PLI_INT32 len_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv; + vpiHandle arg; + + argv = vpi_iterate(vpiArgument, callh); + assert(argv); + arg = vpi_scan(argv); + assert(arg); + vpi_free_object(argv); + + int res = vpi_get(vpiSize, arg); + + s_vpi_value value; + value.format = vpiIntVal; + value.value.integer = res; + + vpi_put_value(callh, &value, 0, vpiNoDelay); + + return 0; +} + +void sys_string_register(void) +{ + s_vpi_systf_data tf_data; + vpiHandle res; + + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiIntFunc; + tf_data.tfname = "$ivl_string_method$len"; + tf_data.calltf = len_calltf; + tf_data.compiletf = one_string_arg_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$ivl_string_method$len"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); +} diff --git a/vpi/sys_table.c b/vpi/sys_table.c index 7010dd85b..0bcb28a41 100644 --- a/vpi/sys_table.c +++ b/vpi/sys_table.c @@ -25,6 +25,7 @@ extern void sys_convert_register(); extern void sys_countdrivers_register(); +extern void sys_darray_register(); extern void sys_fileio_register(); extern void sys_finish_register(); extern void sys_deposit_register(); @@ -34,6 +35,7 @@ extern void sys_queue_register(); extern void sys_random_register(); extern void sys_random_mti_register(); extern void sys_readmem_register(); +extern void sys_string_register(); extern void sys_scanf_register(); extern void sys_sdf_register(); extern void sys_time_register(); @@ -197,6 +199,7 @@ static void sys_lxt_or_vcd_register() void (*vlog_startup_routines[])() = { sys_convert_register, sys_countdrivers_register, + sys_darray_register, sys_fileio_register, sys_finish_register, sys_deposit_register, @@ -207,6 +210,7 @@ void (*vlog_startup_routines[])() = { sys_random_mti_register, sys_readmem_register, sys_scanf_register, + sys_string_register, sys_time_register, sys_lxt_or_vcd_register, sys_sdf_register, diff --git a/vpi/system.sft b/vpi/system.sft index 0b43b1c65..2e65eade3 100644 --- a/vpi/system.sft +++ b/vpi/system.sft @@ -21,3 +21,5 @@ $abstime vpiSysFuncReal $simparam vpiSysFuncReal $simparam$str vpiSysFuncSized 1024 unsigned $table_model vpiSysFuncReal + +$ivl_string_method$len vpiSysFuncInt diff --git a/vpi_user.h b/vpi_user.h index 0660752d1..160df04cf 100644 --- a/vpi_user.h +++ b/vpi_user.h @@ -310,6 +310,12 @@ typedef struct t_vpi_delay { #define vpiVariables 100 #define vpiExpr 102 +/********************** object types added with 1364-2001 *********************/ + +# define vpiRegArray 116 + +/********************** object types added with 1364-2005 *********************/ + #define vpiCallback 1000 /* PROPERTIES */ diff --git a/vvp/Makefile.in b/vvp/Makefile.in index 4f3a59a80..bce54ce01 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -66,8 +66,8 @@ dllib=@DLLIB@ MDIR1 = -DMODULE_DIR1='"$(libdir)/ivl$(suffix)"' -V = vpi_modules.o vpi_callback.o vpi_const.o vpi_event.o vpi_iter.o vpi_mcd.o \ - vpi_priv.o vpi_scope.o vpi_real.o vpi_signal.o vpi_tasks.o vpi_time.o \ +V = vpi_modules.o vpi_callback.o vpi_const.o vpi_darray.o vpi_event.o vpi_iter.o vpi_mcd.o \ + vpi_priv.o vpi_scope.o vpi_real.o vpi_signal.o vpi_string.o vpi_tasks.o vpi_time.o \ vpi_vthr_vector.o vpip_bin.o vpip_hex.o vpip_oct.o \ vpip_to_dec.o vpip_format.o vvp_vpi.o @@ -76,7 +76,7 @@ O = main.o parse.o parse_misc.o lexor.o arith.o array.o bufif.o compile.o \ permaheap.o reduce.o resolv.o \ sfunc.o stop.o symbols.o ufunc.o codes.o vthread.o schedule.o \ statistics.o tables.o udp.o vvp_island.o vvp_net.o vvp_net_sig.o \ - event.o logic.o delay.o words.o island_tran.o $V + vvp_object.o event.o logic.o delay.o words.o island_tran.o $V all: dep vvp@EXEEXT@ libvpi.a vvp.man diff --git a/vvp/README.txt b/vvp/README.txt index a45854ded..329902f6a 100644 --- a/vvp/README.txt +++ b/vvp/README.txt @@ -284,6 +284,7 @@ general syntax of a variable is: