diff --git a/Makefile.in b/Makefile.in index 854054f32..acef67ec7 100644 --- a/Makefile.in +++ b/Makefile.in @@ -109,7 +109,7 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.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 netclass.o netdarray.o \ - netenum.o netparray.o netscalar.o netstruct.o netvector.o \ + netenum.o netparray.o netqueue.o netscalar.o netstruct.o netvector.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.h b/PExpr.h index c8953f694..068cca339 100644 --- a/PExpr.h +++ b/PExpr.h @@ -505,6 +505,11 @@ class PEIdent : public PExpr { NetESignal*net, NetScope*found, bool need_const) const; + NetExpr*elaborate_expr_net_bit_last_(Design*des, + NetScope*scope, + NetESignal*net, + NetScope*found, + bool need_const) const; NetExpr*elaborate_expr_class_member_(Design*des, NetScope*scope, diff --git a/elab_expr.cc b/elab_expr.cc index ea8f19e5d..928cf39c5 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1749,6 +1749,14 @@ static const netstruct_t::member_t*get_struct_member(const LineInfo*li, bool calculate_part(const LineInfo*li, Design*des, NetScope*scope, const index_component_t&index, long&off, unsigned long&wid) { + if (index.sel == index_component_t::SEL_BIT_LAST) { + cerr << li->get_fileline() << ": sorry: " + << "Last element select expression " + << "not supported." << endl; + des->errors += 1; + return false; + } + // Evaluate the last index expression into a constant long. NetExpr*texpr = elab_and_eval(des, scope, index.msb, -1, true); long msb; @@ -2839,21 +2847,31 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) if ((net == 0) || (net->packed_dimensions() <= 1)) use_width = 1; break; + case index_component_t::SEL_BIT_LAST: + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::test_width: " + << "Queue/Darray last index ($)" << endl; + } + break; default: ivl_assert(*this, 0); } if (const netdarray_t*darray = net? net->darray_type() : 0) { - if (use_sel == index_component_t::SEL_BIT) { + switch (use_sel) { + case index_component_t::SEL_BIT: + case index_component_t::SEL_BIT_LAST: expr_type_ = darray->element_base_type(); expr_width_ = darray->element_width(); min_width_ = expr_width_; signed_flag_ = net->get_signed(); - } else { + break; + default: expr_type_ = net->data_type(); expr_width_ = net->vector_width(); min_width_ = expr_width_; signed_flag_ = net->get_signed(); + break; } return expr_width_; } @@ -3917,6 +3935,8 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des, return 0; } + ivl_assert(*this, use_sel != index_component_t::SEL_BIT_LAST); + if (use_sel == index_component_t::SEL_BIT) return elaborate_expr_param_bit_(des, scope, par, found_in, par_msb, par_lsb, need_const); @@ -4645,6 +4665,17 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, return ss; } +NetExpr* PEIdent::elaborate_expr_net_bit_last_(Design*des, NetScope*scope, + NetESignal*net, + NetScope*found_in, + bool need_const) const +{ + cerr << get_fileline() << ": sorry: " + << "Don't yet know how to elaborate net expresion [$]" << endl; + des->errors += 1; + return 0; +} + NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope, NetNet*net, NetScope*found_in, unsigned expr_wid, @@ -4697,6 +4728,10 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope, return elaborate_expr_net_bit_(des, scope, node, found_in, need_const); + if (use_sel == index_component_t::SEL_BIT_LAST) + return elaborate_expr_net_bit_last_(des, scope, node, found_in, + need_const); + // It's not anything else, so this must be a simple identifier // expression with no part or bit select. Return the signal // itself as the expression. diff --git a/elab_sig.cc b/elab_sig.cc index 980e198b1..862f94f4e 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -41,6 +41,7 @@ # include "netvector.h" # include "netdarray.h" # include "netparray.h" +# include "netqueue.h" # include "util.h" # include "ivl_assert.h" @@ -1084,7 +1085,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const listunpacked_dimensions; - netdarray_t*netarray = 0; + netdarray_t*netdarray = 0; for (list::const_iterator cur = unpacked_.begin() ; cur != unpacked_.end() ; ++cur) { @@ -1097,13 +1098,27 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const if (use_lidx==0 && use_ridx==0) { netvector_t*vec = new netvector_t(packed_dimensions, data_type_); packed_dimensions.clear(); - ivl_assert(*this, netarray==0); - netarray = new netdarray_t(vec); + ivl_assert(*this, netdarray==0); + netdarray = new netdarray_t(vec); continue; } + // Special case: Detect the mark for a QUEUE + // declaration, which is the dimensions [null:]. + if (use_ridx==0 && dynamic_cast(use_lidx)) { + netvector_t*vec = new netvector_t(packed_dimensions, data_type_); + packed_dimensions.clear(); + ivl_assert(*this, netdarray==0); + netdarray = new netqueue_t(vec); + continue; + } + + cerr << get_fileline() << ": XXXX: " + << "use_lidx=" << use_lidx + << ", use_ridx=" << use_ridx << endl; + // Cannot handle dynamic arrays of arrays yet. - ivl_assert(*this, netarray==0); + ivl_assert(*this, netdarray==0); ivl_assert(*this, use_lidx && use_ridx); NetExpr*lexp = elab_and_eval(des, scope, use_lidx, -1, true); @@ -1246,7 +1261,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const sig = new NetNet(scope, name_, wtype, unpacked_dimensions, use_enum); - } else if (netarray) { + } else if (netdarray) { if (debug_elaborate) { cerr << get_fileline() << ": debug: Create signal " << wtype @@ -1256,7 +1271,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const ivl_assert(*this, packed_dimensions.empty()); ivl_assert(*this, unpacked_dimensions.empty()); - sig = new NetNet(scope, name_, wtype, netarray); + sig = new NetNet(scope, name_, wtype, netdarray); } else if (parray_type_t*parray_type = dynamic_cast(set_data_type_)) { // The pform gives us a parray_type_t for packed arrays diff --git a/netqueue.cc b/netqueue.cc new file mode 100644 index 000000000..ff68015a1 --- /dev/null +++ b/netqueue.cc @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "netqueue.h" +# include + +using namespace std; + +netqueue_t::netqueue_t(ivl_type_t vec) +: netdarray_t(vec) +{ +} + +netqueue_t::~netqueue_t() +{ +} + +bool netqueue_t::test_compatibility(ivl_type_t that) const +{ + const netqueue_t*that_q = dynamic_cast(that); + if (that_q == 0) + return false; + + return element_type()->type_compatible(that_q->element_type()); +} diff --git a/netqueue.h b/netqueue.h new file mode 100644 index 000000000..7bc126a05 --- /dev/null +++ b/netqueue.h @@ -0,0 +1,40 @@ +#ifndef IVL__netqueue_H +#define IVL__netqueue_H +/* + * Copyright (c) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "netdarray.h" +# include "ivl_target.h" + +/* + * A queue type is actually a dynamic array with a few extra + * methods. This will probably result in a different implementation at + * run-time, but for the most part this applies during elaboration. + */ +class netqueue_t : public netdarray_t { + + public: + explicit netqueue_t(ivl_type_t vec); + ~netqueue_t(); + + private: + bool test_compatibility(ivl_type_t that) const; +}; + +#endif diff --git a/parse.y b/parse.y index 07bd8f189..1f40e609c 100644 --- a/parse.y +++ b/parse.y @@ -2041,10 +2041,8 @@ variable_dimension /* IEEE1800-2005: A.2.5 */ | '[' '$' ']' { // SystemVerilog queue list *tmp = new list; - pform_range_t index (0,0); - if (gn_system_verilog()) { - yyerror("sorry: Dynamic array ranges not supported."); - } else { + pform_range_t index (new PENull,0); + if (!gn_system_verilog()) { yyerror("error: Queue declarations require System Verilog."); } tmp->push_back(index); @@ -3702,6 +3700,20 @@ hierarchy_identifier tail.index.push_back(itmp); $$ = tmp; } + | hierarchy_identifier '[' '$' ']' + { pform_name_t * tmp = $1; + name_component_t&tail = tmp->back(); + if (! gn_system_verilog()) { + yyerror(@3, "error: Last element expression ($) " + "requires SystemVerilog. Try enabling SystemVerilog."); + } + index_component_t itmp; + itmp.sel = index_component_t::SEL_BIT_LAST; + itmp.msb = 0; + itmp.lsb = 0; + tail.index.push_back(itmp); + $$ = tmp; + } | hierarchy_identifier '[' expression ':' expression ']' { pform_name_t * tmp = $1; name_component_t&tail = tmp->back(); diff --git a/pform_dump.cc b/pform_dump.cc index 5cda43ba1..b01966e94 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -62,6 +62,9 @@ ostream& operator<< (ostream&out, const index_component_t&that) case index_component_t::SEL_BIT: out << *that.msb; break; + case index_component_t::SEL_BIT_LAST: + out << "$"; + break; case index_component_t::SEL_PART: out << *that.msb << ":" << *that.lsb; break; diff --git a/pform_types.h b/pform_types.h index d4daa243f..58b46f188 100644 --- a/pform_types.h +++ b/pform_types.h @@ -46,10 +46,40 @@ class ivl_type_s; class netenum_t; typedef named named_number_t; typedef named named_pexpr_t; + +/* + * The pform_range_t holds variable diimensions for type + * declarations. The two expressions are interpreted as the first and + * last values of the range. For example: + * + * [ : ] -- Normal array range + * first == + * second = + * + * [] -- SystemVerilog canonical range + * first = PENumber(0) + * second = - 1; + * + * [ ] -- Dynamic array + * first = 0 + * second = 0 + * + * [ $ ] -- Queue type + * first = PENull + * second = 0 + */ typedef std::pair pform_range_t; +/* + * Semantic NOTES: + * - The SEL_BIT is a single expression. This might me a bit select + * of a vector, or a word select of an array. + * + * - The SEL_BIT_LAST index component is an array/queue [$] index, + * that is the last item in the variable. + */ struct index_component_t { - enum ctype_t { SEL_NONE, SEL_BIT, SEL_PART, SEL_IDX_UP, SEL_IDX_DO }; + enum ctype_t { SEL_NONE, SEL_BIT, SEL_BIT_LAST, SEL_PART, SEL_IDX_UP, SEL_IDX_DO }; index_component_t() : sel(SEL_NONE), msb(0), lsb(0) { }; ~index_component_t() { }