diff --git a/Makefile.in b/Makefile.in index ee1254316..8d1761d92 100644 --- a/Makefile.in +++ b/Makefile.in @@ -108,7 +108,7 @@ 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 \ 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 ec1e67310..266601fdc 100644 --- a/PExpr.h +++ b/PExpr.h @@ -439,6 +439,18 @@ class PEIdent : public PExpr { long&midx, long&lidx) const; }; +class PENew : public PExpr { + + public: + explicit PENew (PExpr*s); + ~PENew(); + + virtual void dump(ostream&) const; + + private: + PExpr*size_; +}; + class PENumber : public PExpr { public: @@ -720,9 +732,13 @@ class PECallFunction : public PExpr { 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; - NetExpr*elaborate_expr_string_method_(Design*des, NetScope*scope) const; +#endif NetExpr* elaborate_sfunc_(Design*des, NetScope*scope, unsigned expr_wid, @@ -731,6 +747,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/design_dump.cc b/design_dump.cc index bd9756ba8..cfe54954b 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()) diff --git a/elab_expr.cc b/elab_expr.cc index 822fa8686..733f59883 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -96,6 +96,7 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, break; case IVL_VT_VOID: case IVL_VT_NO_TYPE: + case IVL_VT_DARRAY: ivl_assert(*expr, 0); break; } @@ -1021,6 +1022,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 +1060,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,6 +1632,13 @@ 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 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; + } +#if 0 // 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. @@ -1597,7 +1654,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, NetExpr*tmp = elaborate_expr_string_method_(des, scope); if (tmp) return tmp; } - +#endif // Nothing was found so report this as an error. cerr << get_fileline() << ": error: No function named `" << path_ << "' found in this context (" << scope_path(scope) << ")." @@ -1736,6 +1793,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; +} +#if 0 NetExpr* PECallFunction::elaborate_expr_enum_method_(Design*des, NetScope*scope, unsigned expr_wid) const { @@ -1775,7 +1890,8 @@ NetExpr* PECallFunction::elaborate_expr_enum_method_(Design*des, NetScope*scope, return 0; } - +#endif +#if 0 NetExpr* PECallFunction::elaborate_expr_string_method_(Design*des, NetScope*scope) const { pform_name_t use_path = path_; @@ -1808,6 +1924,7 @@ NetExpr* PECallFunction::elaborate_expr_string_method_(Design*des, NetScope*scop return 0; } +#endif unsigned PECastSize::test_width(Design*des, NetScope*scope, width_mode_t&) { @@ -3455,7 +3572,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; } diff --git a/elab_lval.cc b/elab_lval.cc index d9ad749a4..c1e853417 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -574,9 +574,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..d421462b2 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_); + 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/ivl_target.h b/ivl_target.h index f025837b5..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; diff --git a/netdarray.cc b/netdarray.cc new file mode 100644 index 000000000..997da92c0 --- /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) +: packed_dims_(packed), type_(type) +{ +} + +netdarray_t::~netdarray_t() +{ +} diff --git a/netdarray.h b/netdarray.h new file mode 100644 index 000000000..b9a968910 --- /dev/null +++ b/netdarray.h @@ -0,0 +1,40 @@ +#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); + ~netdarray_t(); + + ivl_variable_type_t data_type() const { return type_; } + + private: + std::list packed_dims_; + ivl_variable_type_t type_; +}; + +#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..b6aaa3da3 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(); @@ -2399,14 +2435,14 @@ 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 diff --git a/netlist.h b/netlist.h index f688a4427..d18172868 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_; 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 39d97c5c5..b36dc4545 100644 --- a/parse.y +++ b/parse.y @@ -938,12 +938,13 @@ 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; + { //yyerror(@1, "sorry: Dynamic array new expression not supported."); + $$ = new PENew($3); } | 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); } ; @@ -1742,7 +1743,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_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/sv_vpi_user.h b/sv_vpi_user.h index 0bc5ca22f..fadd13a08 100644 --- a/sv_vpi_user.h +++ b/sv_vpi_user.h @@ -50,6 +50,7 @@ EXTERN_C_START #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.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 eaea27751..279d65caa 100644 --- a/tgt-stub/expression.c +++ b/tgt-stub/expression.c @@ -178,7 +178,7 @@ static void show_select_expression(ivl_expr_t net, unsigned ind) 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, "", width); + fprintf(out, "%*sERROR: Width should be a multiple of 8 bits.\n", ind, ""); show_expression(oper1, ind+3); show_expression(oper2, ind+3); diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index 4180a977e..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,26 +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; - case IVL_VT_STRING: data_type = "string"; break; - - default: - data_type = "?data?"; + case IVL_VT_DARRAY: + data_type = "darray"; + break; + case IVL_VT_VOID: + data_type = "void"; break; } @@ -1362,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/vvp_scope.c b/tgt-vvp/vvp_scope.c index 554403436..d87b13bd6 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -502,6 +502,11 @@ 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)), diff --git a/vpi/Makefile.in b/vpi/Makefile.in index e9734d7a1..38d0004a4 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -52,7 +52,8 @@ CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@ LDFLAGS = @LDFLAGS@ # Object files for system.vpi -O = sys_table.o sys_convert.o sys_deposit.o sys_display.o sys_fileio.o \ +O = sys_table.o sys_convert.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_string.o sys_time.o sys_vcd.o sys_vcdoff.o vcd_priv.o mt19937int.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_table.c b/vpi/sys_table.c index 50bafe553..eb8aa63c5 100644 --- a/vpi/sys_table.c +++ b/vpi/sys_table.c @@ -24,6 +24,7 @@ # include extern void sys_convert_register(); +extern void sys_darray_register(); extern void sys_fileio_register(); extern void sys_finish_register(); extern void sys_deposit_register(); @@ -196,6 +197,7 @@ static void sys_lxt_or_vcd_register() void (*vlog_startup_routines[])() = { sys_convert_register, + sys_darray_register, sys_fileio_register, sys_finish_register, sys_deposit_register, diff --git a/vpi_user.h b/vpi_user.h index d0fe2b415..fd91932bc 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 0aed0f35b..f838ff538 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -66,7 +66,7 @@ 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 \ +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 diff --git a/vvp/compile.h b/vvp/compile.h index 56ed79e81..b98e9323a 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -458,6 +458,7 @@ extern void compile_variable(char*label, char*name, extern void compile_var_real(char*label, char*name); extern void compile_var_string(char*label, char*name); +extern void compile_var_darray(char*label, char*name); /* * This function is used to create a scope port diff --git a/vvp/lexor.lex b/vvp/lexor.lex index 05b7502ac..b547cb55d 100644 --- a/vvp/lexor.lex +++ b/vvp/lexor.lex @@ -195,6 +195,7 @@ static char* strdupnew(char const *str) ".ufunc" { return K_UFUNC; } ".ufunc/e" { return K_UFUNC_E; } ".var" { return K_VAR; } +".var/darray" { return K_VAR_DARRAY; } ".var/real" { return K_VAR_R; } ".var/s" { return K_VAR_S; } ".var/str" { return K_VAR_STR; } diff --git a/vvp/parse.y b/vvp/parse.y index 993dc8578..a7bfc7a12 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -91,7 +91,7 @@ static struct __vpiModPath*modpath_dst = 0; %token K_RESOLV K_SCOPE K_SFUNC K_SFUNC_E K_SHIFTL K_SHIFTR K_SHIFTRS %token K_THREAD K_TIMESCALE K_TRAN K_TRANIF0 K_TRANIF1 K_TRANVP %token K_UFUNC K_UFUNC_E K_UDP K_UDP_C K_UDP_S -%token K_VAR K_VAR_S K_VAR_STR K_VAR_I K_VAR_R K_VAR_2S K_VAR_2U +%token K_VAR K_VAR_DARRAY K_VAR_S K_VAR_STR K_VAR_I K_VAR_R K_VAR_2S K_VAR_2U %token K_vpi_call K_vpi_call_w K_vpi_call_i %token K_vpi_func K_vpi_func_r %token K_disable K_fork @@ -702,6 +702,9 @@ statement | T_LABEL K_VAR_STR T_STRING ';' { compile_var_string($1, $3); } + | T_LABEL K_VAR_DARRAY T_STRING ';' + { compile_var_darray($1, $3); } + /* Net statements are similar to .var statements, except that they declare nets, and they have an input list. */ diff --git a/vvp/vpi_darray.cc b/vvp/vpi_darray.cc new file mode 100644 index 000000000..f192d215f --- /dev/null +++ b/vvp/vpi_darray.cc @@ -0,0 +1,87 @@ +/* + * 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 "compile.h" +# include "vpi_priv.h" +# include "vvp_net_sig.h" +# include "schedule.h" +#ifdef CHECK_WITH_VALGRIND +# include "vvp_cleanup.h" +#endif +# include +# include +# include +# include +# include "ivl_alloc.h" + +using namespace std; + +class __vpiDarrayVar : public __vpiHandle { + + public: + __vpiDarrayVar(__vpiScope*scope, const char*name, vvp_net_t*net); + + int get_type_code(void) const; + int vpi_get(int code); + void vpi_get_value(p_vpi_value val); + + inline vvp_net_t* get_net() const { return net_; } + + private: + struct __vpiScope* scope_; + const char*name_; + vvp_net_t*net_; +}; + +__vpiDarrayVar::__vpiDarrayVar(__vpiScope*sc, const char*na, vvp_net_t*ne) +: scope_(sc), name_(na), net_(ne) +{ +} + +int __vpiDarrayVar::get_type_code(void) const +{ return vpiArrayVar; } + + +int __vpiDarrayVar::vpi_get(int code) +{ + vvp_fun_signal_object*fun = dynamic_cast (net_->fun); + assert(fun); + vvp_object_t val = fun->get_object(); + + switch (code) { + default: + return 0; + } +} + +void __vpiDarrayVar::vpi_get_value(p_vpi_value val) +{ + val->format = vpiSuppressVal; +} + +vpiHandle vpip_make_darray_var(const char*name, vvp_net_t*net) +{ + struct __vpiScope*scope = vpip_peek_current_scope(); + const char*use_name = name ? vpip_name_string(name) : 0; + + struct __vpiDarrayVar*obj = new __vpiDarrayVar(scope, use_name, net); + + return obj; +} diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 6b3ee0ef8..c00d7fbc4 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -497,6 +497,8 @@ class __vpiStringVar : public __vpiHandle { extern vpiHandle vpip_make_string_var(const char*name, vvp_net_t*net); +extern vpiHandle vpip_make_darray_var(const char*name, vvp_net_t*net); + /* * When a loaded VPI module announces a system task/function, one * __vpiUserSystf object is created to hold the definition of that diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index 072c8f4cf..cb6971fa1 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -2963,6 +2963,13 @@ void vvp_net_fun_t::recv_string(vvp_net_ptr_t, const std::string&bit, vvp_contex assert(0); } +void vvp_net_fun_t::recv_object(vvp_net_ptr_t, vvp_object_t, vvp_context_t) +{ + fprintf(stderr, "internal error: %s: recv_object(...) not implemented\n", + typeid(*this).name()); + assert(0); +} + void vvp_net_fun_t::force_flag(void) { } diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index d47f1507a..eaf486608 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -23,6 +23,7 @@ # include "vpi_user.h" # include "vvp_vpi_callback.h" # include "permaheap.h" +# include "vvp_object.h" # include # include # include @@ -1083,6 +1084,7 @@ class vvp_net_t { void send_real(double val, vvp_context_t context); void send_long(long val); void send_string(const std::string&val, vvp_context_t context); + void send_object(vvp_object_t val, vvp_context_t context); void send_vec4_pv(const vvp_vector4_t&val, unsigned base, unsigned wid, unsigned vwid, @@ -1159,6 +1161,8 @@ class vvp_net_fun_t { virtual void recv_long(vvp_net_ptr_t port, long bit); virtual void recv_string(vvp_net_ptr_t port, const std::string&bit, vvp_context_t context); + virtual void recv_object(vvp_net_ptr_t port, vvp_object_t bit, + vvp_context_t context); // Part select variants of above virtual void recv_vec4_pv(vvp_net_ptr_t p, const vvp_vector4_t&bit, @@ -1529,6 +1533,18 @@ inline void vvp_send_string(vvp_net_ptr_t ptr, const std::string&val, vvp_contex } } +inline void vvp_send_object(vvp_net_ptr_t ptr, vvp_object_t val, vvp_context_t context) +{ + while (vvp_net_t*cur = ptr.ptr()) { + vvp_net_ptr_t next = cur->port[ptr.port()]; + + if (cur->fun) + cur->fun->recv_object(ptr, val, context); + + ptr = next; + } +} + /* * Part-vector versions of above functions. This function uses the * corresponding recv_vec4_pv method in the vvp_net_fun_t functor to @@ -1676,6 +1692,13 @@ inline void vvp_net_t::send_string(const std::string&val, vvp_context_t context) } +inline void vvp_net_t::send_object(vvp_object_t val, vvp_context_t context) +{ + assert(!fil); + vvp_send_object(out_, val, context); +} + + inline bool vvp_net_fil_t::test_force_mask(unsigned bit) const { if (bit >= force_mask_.size()) diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index 8efb04610..0d0094c5b 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -665,6 +665,80 @@ void vvp_fun_signal_string_aa::operator delete(void*) assert(0); } + /* OBJECT signals */ + +vvp_fun_signal_object_sa::vvp_fun_signal_object_sa() +{ +} + +void vvp_fun_signal_object_sa::recv_object(vvp_net_ptr_t ptr, vvp_object_t bit, + vvp_context_t) +{ + assert(ptr.port() == 0); + + if (needs_init_ || value_ != bit) { + value_ = bit; + needs_init_ = false; + + ptr.ptr()->send_object(bit, 0); + } +} + +vvp_fun_signal_object_aa::vvp_fun_signal_object_aa() +{ + context_idx_ = vpip_add_item_to_context(this, vpip_peek_context_scope()); +} + +vvp_fun_signal_object_aa::~vvp_fun_signal_object_aa() +{ + assert(0); +} + +void vvp_fun_signal_object_aa::alloc_instance(vvp_context_t) +{ + assert(0); +} + +void vvp_fun_signal_object_aa::reset_instance(vvp_context_t) +{ + assert(0); +} + +unsigned vvp_fun_signal_object_aa::value_size() const +{ + assert(0); + return 1; +} + +vvp_bit4_t vvp_fun_signal_object_aa::value(unsigned) const +{ + assert(0); + return BIT4_X; +} + +vvp_scalar_t vvp_fun_signal_object_aa::scalar_value(unsigned) const +{ + assert(0); + return vvp_scalar_t(); +} + +void vvp_fun_signal_object_aa::vec4_value(vvp_vector4_t&) const +{ + assert(0); +} + +void* vvp_fun_signal_object_aa::operator new(std::size_t size) +{ + return vvp_net_fun_t::heap_.alloc(size); +} + +void vvp_fun_signal_object_aa::operator delete(void*) +{ + assert(0); +} + + /* **** */ + vvp_fun_force::vvp_fun_force() { } diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h index a7fb65f98..8e84049a5 100644 --- a/vvp/vvp_net_sig.h +++ b/vvp/vvp_net_sig.h @@ -22,6 +22,7 @@ # include "config.h" # include "vpi_user.h" # include "vvp_net.h" +# include "vvp_object.h" # include # include # include @@ -318,6 +319,62 @@ class vvp_fun_signal_string_aa : public vvp_fun_signal_string, public automatic_ unsigned context_idx_; }; +class vvp_fun_signal_object : public vvp_fun_signal_base { + + public: + explicit vvp_fun_signal_object() {}; + + unsigned size() const { return 1; } + + inline vvp_object_t get_object() const { return value_; } + + protected: + vvp_object_t value_; +}; + +/* + * Statically allocated vvp_fun_signal_string. + */ +class vvp_fun_signal_object_sa : public vvp_fun_signal_object { + + public: + explicit vvp_fun_signal_object_sa(); + + void recv_object(vvp_net_ptr_t port, vvp_object_t bit, + vvp_context_t context); +}; + +/* + * Automatically allocated vvp_fun_signal_real. + */ +class vvp_fun_signal_object_aa : public vvp_fun_signal_object, public automatic_signal_base, public automatic_hooks_s { + + public: + explicit vvp_fun_signal_object_aa(); + ~vvp_fun_signal_object_aa(); + + void alloc_instance(vvp_context_t context); + void reset_instance(vvp_context_t context); +#ifdef CHECK_WITH_VALGRIND + void free_instance(vvp_context_t context); +#endif + + // Get information about the vector value. + unsigned value_size() const; + vvp_bit4_t value(unsigned idx) const; + vvp_scalar_t scalar_value(unsigned idx) const; + void vec4_value(vvp_vector4_t&) const; + //double real_value() const; + //void get_signal_value(struct t_vpi_value*vp); + + public: // These objects are only permallocated. + static void* operator new(std::size_t size); + static void operator delete(void*obj); + + private: + unsigned context_idx_; +}; + /* vvp_wire * The vvp_wire is different from vvp_variable objects in that it diff --git a/vvp/vvp_object.h b/vvp/vvp_object.h new file mode 100644 index 000000000..fe5bb0bd9 --- /dev/null +++ b/vvp/vvp_object.h @@ -0,0 +1,24 @@ +#ifndef __vvp_object_H +#define __vvp_object_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 + */ + +typedef class vvp_object*vvp_object_t; + +#endif diff --git a/vvp/words.cc b/vvp/words.cc index f77529bbb..8ac96fbce 100644 --- a/vvp/words.cc +++ b/vvp/words.cc @@ -114,6 +114,42 @@ void compile_var_string(char*label, char*name) __compile_var_string(label, name, 0, 0); } +static void __compile_var_darray(char*label, char*name, + vvp_array_t array, unsigned long array_addr) +{ + vvp_net_t*net = new vvp_net_t; + + if (vpip_peek_current_scope()->is_automatic) { + vvp_fun_signal_object_aa*tmp = new vvp_fun_signal_object_aa; + net->fil = tmp; + net->fun = tmp; + } else { + net->fil = 0; + net->fun = new vvp_fun_signal_object_sa; + } + + define_functor_symbol(label, net); + + vpiHandle obj = vpip_make_darray_var(name, net); + compile_vpi_symbol(label, obj); + + if (name) { + assert(!array); + vpip_attach_to_current_scope(obj); + } + if (array) { + assert(!name); + array_attach_word(array, array_addr, obj); + } + delete[]label; + delete[] name; +} + +void compile_var_darray(char*label, char*name) +{ + __compile_var_darray(label, name, 0, 0); +} + /* * A variable is a special functor, so we allocate that functor and * write the label into the symbol table.