diff --git a/HName.cc b/HName.cc index 709528489..c783d57bb 100644 --- a/HName.cc +++ b/HName.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-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 @@ -22,22 +22,26 @@ # include # include # include -# include +using namespace std; hname_t::hname_t() { - number_ = INT_MIN; } hname_t::hname_t(perm_string text) : name_(text) { - number_ = INT_MIN; } hname_t::hname_t(perm_string text, int num) -: name_(text), number_(num) +: name_(text), number_(1) +{ + number_[0] = num; +} + +hname_t::hname_t(perm_string text, vector&nums) +: name_(text), number_(nums) { } @@ -53,24 +57,50 @@ hname_t& hname_t::operator = (const hname_t&that) return *this; } -bool operator < (const hname_t&l, const hname_t&r) +bool hname_t::operator < (const hname_t&r) const { - int cmp = strcmp(l.peek_name(), r.peek_name()); + int cmp = strcmp(name_, r.name_); if (cmp < 0) return true; if (cmp > 0) return false; - if (l.has_number() && r.has_number()) - return l.peek_number() < r.peek_number(); - else - return false; + + // The text parts are equal, so compare then number + // parts. Finish as soon as we find one to be less or more + // than the other. + size_t idx = 0; + while (number_.size() > idx || r.number_.size() > idx) { + + // Ran out of l numbers, so less. + if (number_.size() <= idx) + return true; + + // Ran out of r numbers, so greater. + if (r.number_.size() <= idx) + return false; + + if (number_[idx] < r.number_[idx]) + return true; + + if (number_[idx] > r.number_[idx]) + return false; + + idx += 1; + } + + // Fall-through means that we are equal, including all the + // number parts, so not less. + return false; } -bool operator == (const hname_t&l, const hname_t&r) +bool hname_t::operator == (const hname_t&r) const { - if (l.peek_name() == r.peek_name()) { - if (l.has_number() && r.has_number()) - return l.peek_number() == r.peek_number(); - else - return true; + if (name_ == r.name_) { + if (number_.size() != r.number_.size()) + return false; + + for (size_t idx = 0 ; idx < number_.size() ; idx += 1) + if (number_[idx] != r.number_[idx]) return false; + + return true; } return false; @@ -84,8 +114,8 @@ ostream& operator<< (ostream&out, const hname_t&that) } out << that.peek_name(); - if (that.has_number()) - out << "[" << that.peek_number() << "]"; + for (size_t idx = 0 ; idx < that.number_.size() ; idx += 1) + out << "[" << that.number_[idx] << "]"; return out; } diff --git a/HName.h b/HName.h index ce561f8f0..6d1f3ccb7 100644 --- a/HName.h +++ b/HName.h @@ -1,7 +1,7 @@ #ifndef __HName_H #define __HName_H /* - * Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-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 @@ -21,13 +21,10 @@ # include # include +# include # include "StringHeap.h" -# include -#ifdef __GNUC__ -#if __GNUC__ > 2 -using namespace std; -#endif -#endif + +# include /* * This class represents a component of a Verilog hierarchical name. A @@ -39,27 +36,33 @@ using namespace std; class hname_t { + friend ostream& operator<< (ostream&out, const hname_t&that); + public: hname_t (); explicit hname_t (perm_string text); explicit hname_t (perm_string text, int num); + explicit hname_t (perm_string text, std::vector&nums); hname_t (const hname_t&that); ~hname_t(); hname_t& operator= (const hname_t&); + bool operator == (const hname_t&that) const; + bool operator < (const hname_t&that) const; + // Return the string part of the hname_t. perm_string peek_name(void) const; - bool has_number() const; - int peek_number() const; + size_t has_numbers() const; + int peek_number(size_t idx) const; private: perm_string name_; // If the number is anything other than INT_MIN, then this is // the numeric part of the name. Otherwise, it is not part of // the name at all. - int number_; + std::vector number_; private: // not implemented }; @@ -73,18 +76,17 @@ inline perm_string hname_t::peek_name(void) const return name_; } -inline int hname_t::peek_number() const +inline int hname_t::peek_number(size_t idx) const { - return number_; + assert(number_.size() > idx); + return number_[idx]; } -inline bool hname_t::has_number() const +inline size_t hname_t::has_numbers() const { - return number_ != INT_MIN; + return number_.size(); } -extern bool operator < (const hname_t&, const hname_t&); -extern bool operator == (const hname_t&, const hname_t&); extern ostream& operator<< (ostream&, const hname_t&); inline bool operator != (const hname_t&l, const hname_t&r) diff --git a/PExpr.h b/PExpr.h index 5b014de8a..556dd3491 100644 --- a/PExpr.h +++ b/PExpr.h @@ -366,6 +366,11 @@ class PEIdent : public PExpr { // only applies to Ident expressions. NetNet* elaborate_subport(Design*des, NetScope*sc) const; + // Elaborate the identifier allowing for unpacked arrays. This + // method only applies to Ident expressions because only Ident + // expressions can can be unpacked arrays. + NetNet* elaborate_unpacked_net(Design*des, NetScope*sc) const; + verinum* eval_const(Design*des, NetScope*sc) const; virtual bool is_collapsible_net(Design*des, NetScope*scope) const; diff --git a/PGate.h b/PGate.h index 85ea1194b..7b726fa68 100644 --- a/PGate.h +++ b/PGate.h @@ -124,6 +124,7 @@ class PGAssign : public PGate { virtual bool elaborate_sig(Design*des, NetScope*scope) const; private: + void elaborate_unpacked_array_(Design*des, NetScope*scope, NetNet*lval) const; }; diff --git a/design_dump.cc b/design_dump.cc index e42347bcb..9a8a256d7 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -145,6 +145,35 @@ ostream& operator << (ostream&o, ivl_switch_type_t val) return o; } +ostream& operator << (ostream&fd, PortType::Enum val) +{ + switch (val) { + case PortType::NOT_A_PORT: + fd << "NOT_A_PORT"; + break; + case PortType::PIMPLICIT: + fd << "PIMPLICIT"; + break; + case PortType::PINPUT: + fd << "PINPUT"; + break; + case PortType::POUTPUT: + fd << "POUTPUT"; + break; + case PortType::PINOUT: + fd << "PINOUT"; + break; + case PortType::PREF: + fd << "PREF"; + break; + default: + fd << "PortType::Enum::?"; + break; + } + + return fd; +} + ostream& ivl_type_s::debug_dump(ostream&o) const { o << typeid(*this).name(); @@ -171,9 +200,7 @@ static inline void dump_scope_path(ostream&o, const NetScope*scope) o << "."; } const hname_t name = scope->fullname(); - o << name.peek_name(); - if (name.has_number()) - o << "[" << name.peek_number() << "]"; + o << name; } ostream& operator <<(ostream&o, struct __ScopePathManip marg) diff --git a/elab_expr.cc b/elab_expr.cc index bee085511..481430024 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1790,6 +1790,11 @@ bool calculate_part(const LineInfo*li, Design*des, NetScope*scope, } return true; + case index_component_t::SEL_IDX_UP: + wid = lsb; + off = msb; + break; + default: ivl_assert(*li, 0); break; @@ -2585,6 +2590,7 @@ bool PEIdent::calculate_packed_indices_(Design*des, NetScope*scope, NetNet*net, { list index; index = path_.back().index; + ivl_assert(*this, index.size() >= net->unpacked_dimensions()); for (size_t idx = 0 ; idx < net->unpacked_dimensions() ; idx += 1) index.pop_front(); @@ -2826,7 +2832,10 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) const index_component_t&index_tail = name_tail.index.back(); ivl_assert(*this, index_tail.msb); } - use_width = 1; + // If we have a net in hand, then we can predict what + // the slice width will be. If not, then just guess. + if (net == 0) + use_width = 1; break; default: ivl_assert(*this, 0); @@ -2858,15 +2867,35 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) // The width of a signal expression is the width of the signal. if (net != 0) { + size_t use_depth = name_tail.index.size(); + // Account for unpacked dimensions by assuming that the + // unpacked dimensions are consumed first, so subtract + // the unpacked dimensions from the dimension depth + // useable for making the slice. + if (use_depth >= net->unpacked_dimensions()) { + use_depth -= net->unpacked_dimensions(); + + } else { + // In this case, we have a slice of an unpacked + // array. This likely handled as an array instead + // of a slice. Hmm... + use_depth = 0; + } + expr_type_ = net->data_type(); - expr_width_ = net->vector_width(); + expr_width_ = net->slice_width(use_depth); min_width_ = expr_width_; signed_flag_ = net->get_signed(); if (debug_elaborate) { cerr << get_fileline() << ": PEIdent::test_width: " << net->name() << " is a net, " << "type=" << expr_type_ - << ", width=" << expr_width_ << endl; + << ", width=" << expr_width_ + << ", signed_=" << (signed_flag_?"true":"false") + << ", use_depth=" << use_depth + << ", packed_dimensions=" << net->packed_dimensions() + << ", unpacked_dimensions=" << net->unpacked_dimensions() + << endl; } return expr_width_; } @@ -3222,6 +3251,13 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, if (!tmp) return 0; + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_expr: " + << "Expression as net. expr_wid=" << expr_wid + << ", tmp->expr_width()=" << tmp->expr_width() + << ", tmp=" << *tmp << endl; + } + tmp = pad_to_width(tmp, expr_wid, *this); tmp->cast_signed(signed_flag_); @@ -3969,7 +4005,7 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope, if (name_tail.index.empty()) { cerr << get_fileline() << ": error: Array " << path() - << " Needs an array index here." << endl; + << " needs an array index here." << endl; des->errors += 1; return 0; } @@ -4439,6 +4475,15 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, // making a mux part in the netlist. if (NetEConst*msc = dynamic_cast (mux)) { + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_expr_net_bit_: " + << "mux is constant=" << *msc + << ", packed_dims()=" << net->sig()->packed_dims() + << ", packed_dims().size()=" << net->sig()->packed_dims().size() + << ", prefix_indices.size()=" << prefix_indices.size() + << endl; + } + // Special case: The bit select expression is constant // x/z. The result of the expression is 1'bx. if (! msc->value().is_defined()) { @@ -4456,6 +4501,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, << endl; } + // FIXME: Should I be using slice_width() here? NetEConst*tmp = make_const_x(1); tmp->set_line(*this); delete mux; @@ -4547,6 +4593,12 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, if (net->vector_width() == 1) return net; + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_expr_net_bit_: " + << "Make bit select idx=" << idx + << endl; + } + // Make an expression out of the index NetEConst*idx_c = new NetEConst(verinum(idx)); idx_c->set_line(*net); diff --git a/elab_net.cc b/elab_net.cc index 1cad8de9c..cbaf15202 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -501,6 +501,10 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, unsigned midx = sig->vector_width()-1, lidx = 0; // The default word select is the first. long widx = 0; + // Set this to true if we calculate the word index. This is + // used to distinguish between unpacked array assignment and + // array word assignment. + bool widx_flag = false; list unpacked_indices_const; @@ -555,8 +559,9 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, packed_base = collapse_array_indices(des, scope, sig, tmp_index); if (debug_elaborate) { - cerr << get_fileline() << ": debug: " - << "packed_base expression = " << *packed_base << endl; + cerr << get_fileline() << ": PEIdent::elaborate_lnet_common_: " + << "packed_base=" << *packed_base + << ", member_off=" << member_off << endl; } } @@ -590,13 +595,31 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, midx = lidx + tmp_wid - 1; } + } else if (gn_system_verilog() && sig->unpacked_dimensions() > 0 && path_tail.index.size() == 0) { + + // In this case, we are doing a continuous assignment to + // an unpacked array. The NetNet representation is a + // NetNet with a pin for each array element, so there is + // nothing more needed here. + // + // This can come up from code like this: + // logic [...] data [0:3]; + // assign data = ...; + // In this case, "sig" is "data", and sig->pin_count() + // is 4 to account for the unpacked size. + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_lnet_common_: " + << "Net assign to unpacked array \"" << sig->name() + << "\" with " << sig->pin_count() << " elements." << endl; + } + } else if (sig->unpacked_dimensions() > 0) { // Make sure there are enough indices to address an array element. if (path_tail.index.size() < sig->unpacked_dimensions()) { cerr << get_fileline() << ": error: Array " << path() << " needs " << sig->unpacked_dimensions() << " indices," - << " but got only " << path_tail.index.size() << "." << endl; + << " but got only " << path_tail.index.size() << ". (net)" << endl; des->errors += 1; return 0; } @@ -627,6 +650,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, << sig->name() << as_indices(unpacked_indices) << "." << endl; widx = -1; + widx_flag = true; } else { NetExpr*canon_index = 0; @@ -639,12 +663,14 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, << sig->name() << as_indices(unpacked_indices_const) << "." << endl; widx = -1; + widx_flag = true; } else { NetEConst*canon_const = dynamic_cast(canon_index); ivl_assert(*this, canon_const); widx = canon_const->value().as_long(); + widx_flag = true; delete canon_index; } } @@ -682,6 +708,16 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, } } else if (!path_tail.index.empty()) { + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_lnet_common_: " + << "path_tail.index.size()=" << path_tail.index.size() + << endl; + } + + // There are index expressions on the name, so this is a + // bit/slice select of the name. Calculate a canonical + // part select. + if (sig->get_scalar()) { cerr << get_fileline() << ": error: " << "can not select part of "; @@ -710,14 +746,21 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, unsigned subnet_wid = midx-lidx+1; /* Check if the l-value bits are double-driven. */ - if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->test_and_set_part_driver(midx,lidx)) { + if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->test_and_set_part_driver(midx,lidx, widx_flag? widx : 0)) { cerr << get_fileline() << ": error: Unresolved net/uwire " << sig->name() << " cannot have multiple drivers." << endl; + if (debug_elaborate) { + cerr << get_fileline() << ": : Overlap in " + << "[" << midx << ":" << lidx << "] (canonical)" + << ", widx=" << (widx_flag? widx : 0) + << ", vector width=" << sig->vector_width() + << endl; + } des->errors += 1; return 0; } - if (sig->pin_count() > 1) { + if (sig->pin_count() > 1 && widx_flag) { if (widx < 0 || widx >= (long) sig->pin_count()) return 0; @@ -729,6 +772,13 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, tmp->local_flag(true); connect(sig->pin(widx), tmp->pin(0)); sig = tmp; + + } else if (sig->pin_count() > 1) { + + // If this turns out to be an l-value unpacked array, + // then let the caller handle it. It will probably be + // converted into an array of assignments. + return sig; } /* If the desired l-value vector is narrower than the @@ -851,6 +901,33 @@ NetNet* PEIdent::elaborate_subport(Design*des, NetScope*scope) const long midx; long lidx; + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_subport: " + << "path_ = \"" << path_ + << "\", unpacked_dimensions=" << sig->unpacked_dimensions() + << ", port_type()=" << sig->port_type() << endl; + } + + if (sig->unpacked_dimensions() && !gn_system_verilog()) { + cerr << get_fileline() << ": error: " + << "Ports cannot be unpacked arrays. Try enabling SystemVerilog support." << endl; + des->errors += 1; + return 0; + } + + // There cannot be parts to an unpacked array, so process this + // simply as an unpacked array. + if (sig->unpacked_dimensions()) { + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_subport: " + << "path_=\"" << path_ + << "\" is an unpacked array with " << sig->pin_count() + << " elements." << endl; + } + scope->add_module_port_net(sig); + return sig; + } + /* Evaluate the part/bit select expressions, to get the part select of the signal that attaches to the port. Also handle range and direction checking here. */ @@ -912,6 +989,20 @@ NetNet* PEIdent::elaborate_subport(Design*des, NetScope*scope) const return sig; } +NetNet*PEIdent::elaborate_unpacked_net(Design*des, NetScope*scope) const +{ + NetNet* sig = 0; + const NetExpr*par = 0; + NetEvent* eve = 0; + perm_string method_name; + + symbol_search(this, des, scope, path_, sig, par, eve); + + ivl_assert(*this, sig); + + return sig; +} + bool PEIdent::is_collapsible_net(Design*des, NetScope*scope) const { assert(scope); diff --git a/elab_scope.cc b/elab_scope.cc index 1b78ac894..2d70d938b 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -883,8 +883,10 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container) // Check the generate block name. - // A generate "loop" can not have the same name as another scope object. - const NetScope *child = container->child(hname_t(scope_name)); + // A generate "loop" can not have the same name as another + // scope object. Find any scope with this name, not just an + // exact match scope. + const NetScope *child = container->child_byname(scope_name); if (child) { cerr << get_fileline() << ": error: generate \"loop\" and "; child->print_type(cerr); diff --git a/elab_sig.cc b/elab_sig.cc index 4b8b0ec36..2d6fdcf9b 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -949,7 +949,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const des->errors += error_cnt_; // A signal can not have the same name as a scope object. - const NetScope *child = scope->child(hname_t(name_)); + const NetScope *child = scope->child_byname(name_); if (child) { cerr << get_fileline() << ": error: signal and "; child->print_type(cerr); diff --git a/elaborate.cc b/elaborate.cc index 66f346853..4c203db17 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -77,11 +77,19 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const return; } + // If this turns out to be an assignment to an unpacked array, + // then handle that special case elsewhere. + if (lval->pin_count() > 1) { + elaborate_unpacked_array_(des, scope, lval); + return; + } + ivl_assert(*this, lval->pin_count() == 1); if (debug_elaborate) { - cerr << get_fileline() << ": debug: PGAssign: elaborated l-value" - << " width=" << lval->vector_width() << endl; + cerr << get_fileline() << ": PGAssign::elaborate: elaborated l-value" + << " width=" << lval->vector_width() + << ", pin_count=" << lval->pin_count() << endl; } NetExpr*rval_expr = elaborate_rval_expr(des, scope, lval->net_type(), @@ -211,6 +219,18 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const } +void PGAssign::elaborate_unpacked_array_(Design*des, NetScope*scope, NetNet*lval) const +{ + PEIdent*rval_pident = dynamic_cast (pin(1)); + ivl_assert(*this, rval_pident); + + NetNet*rval_net = rval_pident->elaborate_unpacked_net(des, scope); + + ivl_assert(*this, rval_net->pin_count() == lval->pin_count()); + + assign_unpacked_with_bufz(des, scope, this, lval, rval_net); +} + unsigned PGBuiltin::calculate_array_count_(Design*des, NetScope*scope, long&high, long&low) const { @@ -1350,18 +1370,22 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const unsigned int prt_vector_width = 0; PortType::Enum ptype = PortType::PIMPLICIT; // Scan the module sub-ports for this instance... + // (Sub-ports are concatenated ports that form the + // single port for the instance. This is not a + // commonly used feature.) for (unsigned ldx = 0 ; ldx < mport.size() ; ldx += 1) { unsigned lbase = inst * mport.size(); PEIdent*pport = mport[ldx]; - assert(pport); + ivl_assert(*this, pport); NetNet *netnet = pport->elaborate_subport(des, inst_scope); prts[lbase + ldx] = netnet; if (netnet == 0) continue; - assert(netnet); - prts_vector_width += netnet->vector_width(); - prt_vector_width += netnet->vector_width(); + ivl_assert(*this, netnet); + unsigned port_width = netnet->vector_width() * netnet->pin_count(); + prts_vector_width += port_width; + prt_vector_width += port_width; ptype = PortType::merged(netnet->port_type(), ptype); } inst_scope->add_module_port_info(idx, rmod->get_port_name(idx), ptype, prt_vector_width ); @@ -1392,9 +1416,25 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const // module[s] port. sig is the thing outside the module // that connects to the port. - NetNet*sig; + NetNet*sig = 0; if (prts.empty() || (prts[0]->port_type() == NetNet::PINPUT)) { + // Special case: If the input port is an unpacked + // array, then there should be no sub-ports and + // the r-value expression is processed + // differently. + if (prts.size() >= 1 && prts[0]->pin_count()>1) { + ivl_assert(*this, prts.size()==1); + + PEIdent*rval_pident = dynamic_cast (pins[idx]); + ivl_assert(*this, rval_pident); + + NetNet*rval_net = rval_pident->elaborate_unpacked_net(des, scope); + ivl_assert(*this, rval_net->pin_count() == prts[0]->pin_count()); + assign_unpacked_with_bufz(des, scope, this, prts[0], rval_net); + continue; + } + /* Input to module. elaborate the expression to the desired width. If this in an instance array, then let the net determine its own @@ -1471,6 +1511,9 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const } else if (prts[0]->port_type() == NetNet::PINOUT) { + // For now, do not support unpacked array outputs. + ivl_assert(*this, prts[0]->unpacked_dimensions()==0); + /* Inout to/from module. This is a more complicated case, where the expression must be an lnet, but also an r-value net. @@ -1530,6 +1573,28 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const /* Port type must be OUTPUT here. */ ivl_assert(*this, prts[0]->port_type() == NetNet::POUTPUT); + // Special case: If the output port is an unpacked + // array, then there should be no sub-ports and + // the passed pexxpression is processed + // differently. Note that we are calling it the + // "r-value" expression, but since this is an + // output port, we assign to it from the internal object. + if (prts[0]->pin_count() > 1) { + ivl_assert(*this, prts.size()==1); + + PEIdent*rval_pident = dynamic_cast(pins[idx]); + ivl_assert(*this, rval_pident); + + NetNet*rval_net = rval_pident->elaborate_unpacked_net(des, scope); + ivl_assert(*this, rval_net->pin_count() == prts[0]->pin_count()); + + assign_unpacked_with_bufz(des, scope, this, rval_net, prts[0]); + continue; + } + + // At this point, arrays are handled. + ivl_assert(*this, prts[0]->unpacked_dimensions()==0); + /* Output from module. Elaborate the port expression as the l-value of a continuous assignment, as the port will continuous assign @@ -5812,7 +5877,9 @@ Design* elaborate(listroots) // stuff to the design that should be cleaned later. NetNet *netnet = mport[pin]->elaborate_subport(des, scope); if (netnet != 0) { - // Elaboration may actually fail with erroneous input source + // Elaboration may actually fail with + // erroneous input source + ivl_assert(*mport[pin], netnet->pin_count()==1); prt_vector_width += netnet->vector_width(); ptype = PortType::merged(netnet->port_type(), ptype); } diff --git a/lexor.lex b/lexor.lex index 68435444c..dbcb6a251 100644 --- a/lexor.lex +++ b/lexor.lex @@ -325,8 +325,8 @@ TU [munpf] if (in_package_scope) { if (rc == IDENTIFIER) { if (data_type_t*type = pform_test_type_identifier(in_package_scope, yylval.text)) { - delete[]yylval.text; - yylval.data_type = type; + yylval.type_identifier.text = yylval.text; + yylval.type_identifier.type = type; rc = TYPE_IDENTIFIER; } } @@ -361,8 +361,8 @@ TU [munpf] return this as a TYPE_IDENTIFIER instead. */ if (rc == IDENTIFIER && gn_system_verilog()) { if (data_type_t*type = pform_test_type_identifier(yylval.text)) { - delete[]yylval.text; - yylval.data_type = type; + yylval.type_identifier.text = yylval.text; + yylval.type_identifier.type = type; rc = TYPE_IDENTIFIER; } } @@ -382,8 +382,8 @@ TU [munpf] } if (gn_system_verilog()) { if (data_type_t*type = pform_test_type_identifier(yylval.text)) { - delete[]yylval.text; - yylval.data_type = type; + yylval.type_identifier.text = yylval.text; + yylval.type_identifier.type = type; return TYPE_IDENTIFIER; } } diff --git a/net_scope.cc b/net_scope.cc index e72a31133..ba9782a56 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -668,6 +668,21 @@ const NetScope* NetScope::child(const hname_t&name) const return cur->second; } +const NetScope* NetScope::child_byname(perm_string name) const +{ + hname_t hname (name); + map::const_iterator cur = children_.lower_bound(hname); + + if (cur == children_.end()) + return 0; + + if (cur->first.peek_name() == name) + return cur->second; + + return 0; +} + + perm_string NetScope::local_symbol() { ostringstream res; diff --git a/netlist.cc b/netlist.cc index e66c9c7c9..4d184dc51 100644 --- a/netlist.cc +++ b/netlist.cc @@ -762,6 +762,9 @@ const netclass_t* NetNet::class_type(void) const * In this case, slice_width(2) == 1 (slice_width(N) where N is the * number of dimensions will always be 1.) and represents * $bits(foo[a][b]). Then, slice_width(1)==4 ($bits(foo[a]) and slice_width(0)==24. + * + * NOTE: The caller should already have accounted for unpacked + * dimensions. The "depth" is only for the packed dimensions. */ unsigned long NetNet::slice_width(size_t depth) const { @@ -868,17 +871,25 @@ unsigned NetNet::peek_eref() const * Test each of the bits in the range, and set them. If any bits are * already set then return true. */ -bool NetNet::test_and_set_part_driver(unsigned pmsb, unsigned plsb) +bool NetNet::test_and_set_part_driver(unsigned pmsb, unsigned plsb, int widx) { if (lref_mask_.empty()) - lref_mask_.resize(vector_width()); + lref_mask_.resize(vector_width() * pin_count()); + + // If indexing a word that doesn't exist, then pretend this is + // never driven. + if (widx < 0) + return false; + if (widx >= (int)pin_count()) + return false; bool rc = false; + unsigned word_base = vector_width() * widx; for (unsigned idx = plsb ; idx <= pmsb ; idx += 1) { - if (lref_mask_[idx]) + if (lref_mask_[idx+word_base]) rc = true; else - lref_mask_[idx] = true; + lref_mask_[idx+word_base] = true; } return rc; diff --git a/netlist.h b/netlist.h index 6cefc4c15..4f49bf9b2 100644 --- a/netlist.h +++ b/netlist.h @@ -610,6 +610,7 @@ public: static Enum merged( Enum lhs, Enum rhs ); }; +extern std::ostream& operator << (std::ostream&, PortType::Enum); /* * Information on actual ports (rather than port-connected signals) of @@ -749,8 +750,10 @@ class NetNet : public NetObj, public PortType { // Treating this node as a uwire, this function tests whether // any bits in the canonical part are already driven. This is - // only useful for UNRESOLVED_WIRE objects. - bool test_and_set_part_driver(unsigned msb, unsigned lsb); + // only useful for UNRESOLVED_WIRE objects. The msb and lsb + // are the part select of the signal, and the widx is the word + // index if this is an unpacked array. + bool test_and_set_part_driver(unsigned msb, unsigned lsb, int widx =0); unsigned get_refs() const; @@ -963,6 +966,12 @@ class NetScope : public Definitions, public Attrib { const NetScope* parent() const { return up_; } const NetScope* child(const hname_t&name) const; + // Look for a child scope by name. This ignores the number + // part of the child scope name, so there may be multiple + // matches. Only return one. This function is only really + // useful for some elaboration error checking. + const NetScope* child_byname(perm_string name) const; + // Nested modules have slightly different scope search rules. inline bool nested_module() const { return nested_module_; } // Program blocks have elaboration constraints. diff --git a/netmisc.cc b/netmisc.cc index 91c974184..ec08cffdf 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -309,7 +309,7 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb, if (min_wid < base->expr_width()) min_wid = base->expr_width(); /* Now that we have the minimum needed width increase it by * one to make room for the normalization calculation. */ - min_wid += 1; + min_wid += 2; /* Pad the base expression to the correct width. */ base = pad_to_width(base, min_wid, *base); /* If the base expression is unsigned and either the lsb @@ -344,7 +344,7 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb, if (min_wid < base->expr_width()) min_wid = base->expr_width(); /* Now that we have the minimum needed width increase it by * one to make room for the normalization calculation. */ - min_wid += 1; + min_wid += 2; /* Pad the base expression to the correct width. */ base = pad_to_width(base, min_wid, *base); /* If the offset is greater than zero then we need to do @@ -950,50 +950,48 @@ hname_t eval_path_component(Design*des, NetScope*scope, if (comp.index.empty()) return hname_t(comp.name); - // The parser will assure that path components will have only - // one index. For example, foo[N] is one index, foo[n][m] is two. - assert(comp.index.size() == 1); + vector index_values; - const index_component_t&index = comp.index.front(); + for (list::const_iterator cur = comp.index.begin() + ; cur != comp.index.end() ; ++cur) { + const index_component_t&index = *cur; - if (index.sel != index_component_t::SEL_BIT) { - cerr << index.msb->get_fileline() << ": error: " - << "Part select is not valid for this kind of object." << endl; - des->errors += 1; - return hname_t(comp.name, 0); - } + if (index.sel != index_component_t::SEL_BIT) { + cerr << index.msb->get_fileline() << ": error: " + << "Part select is not valid for this kind of object." << endl; + des->errors += 1; + return hname_t(comp.name, 0); + } - // The parser will assure that path components will have only - // bit select index expressions. For example, "foo[n]" is OK, - // but "foo[n:m]" is not. - assert(index.sel == index_component_t::SEL_BIT); + // The parser will assure that path components will have only + // bit select index expressions. For example, "foo[n]" is OK, + // but "foo[n:m]" is not. + assert(index.sel == index_component_t::SEL_BIT); - // Evaluate the bit select to get a number. - NetExpr*tmp = elab_and_eval(des, scope, index.msb, -1); - ivl_assert(*index.msb, tmp); - - // Now we should have a constant value for the bit select - // expression, and we can use it to make the final hname_t - // value, for example "foo[5]". - if (NetEConst*ctmp = dynamic_cast(tmp)) { - hname_t res(comp.name, ctmp->value().as_long()); - delete ctmp; - return res; - } + // Evaluate the bit select to get a number. + NetExpr*tmp = elab_and_eval(des, scope, index.msb, -1); + ivl_assert(*index.msb, tmp); + if (NetEConst*ctmp = dynamic_cast(tmp)) { + index_values.push_back(ctmp->value().as_long()); + delete ctmp; + continue; + } #if 1 - // Darn, the expression doesn't evaluate to a constant. That's - // an error to be reported. And make up a fake index value to - // return to the caller. - cerr << index.msb->get_fileline() << ": error: " - << "Scope index expression is not constant: " - << *index.msb << endl; - des->errors += 1; + // Darn, the expression doesn't evaluate to a constant. That's + // an error to be reported. And make up a fake index value to + // return to the caller. + cerr << index.msb->get_fileline() << ": error: " + << "Scope index expression is not constant: " + << *index.msb << endl; + des->errors += 1; #endif - error_flag = true; + error_flag = true; - delete tmp; - return hname_t (comp.name, 0); + delete tmp; + } + + return hname_t(comp.name, index_values); } std::list eval_scope_path(Design*des, NetScope*scope, @@ -1338,3 +1336,21 @@ NetExpr*collapse_array_indices(Design*des, NetScope*scope, NetNet*net, eval_expr(res, -1); return res; } + +void assign_unpacked_with_bufz(Design*des, NetScope*scope, + const LineInfo*loc, + NetNet*lval, NetNet*rval) +{ + ivl_assert(*loc, lval->pin_count()==rval->pin_count()); + + for (unsigned idx = 0 ; idx < lval->pin_count() ; idx += 1) { + NetBUFZ*driver = new NetBUFZ(scope, scope->local_symbol(), + lval->vector_width(), false); + driver->set_line(*loc); + des->add_node(driver); + + connect(lval->pin(idx), driver->pin(0)); + connect(driver->pin(1), rval->pin(idx)); + } +} + diff --git a/netmisc.h b/netmisc.h index 90d73cb9c..1eb6ad717 100644 --- a/netmisc.h +++ b/netmisc.h @@ -349,4 +349,8 @@ extern NetExpr*collapse_array_exprs(Design*des, NetScope*scope, const LineInfo*loc, NetNet*net, const list&indices); +extern void assign_unpacked_with_bufz(Design*des, NetScope*scope, + const LineInfo*loc, + NetNet*lval, NetNet*rval); + #endif diff --git a/netparray.cc b/netparray.cc index d8779a92d..326b549fc 100644 --- a/netparray.cc +++ b/netparray.cc @@ -49,7 +49,7 @@ vector netparray_t::slice_dimensions() const vector res (packed_dims_.size() + elem_dims.size()); for (size_t idx = 0 ; idx < packed_dims_.size() ; idx += 1) - res[idx] = packed_dims_[0]; + res[idx] = packed_dims_[idx]; for (size_t idx = 0 ; idx < elem_dims.size() ; idx += 1) res[idx+packed_dims_.size()] = elem_dims[idx]; diff --git a/nettypes.cc b/nettypes.cc index 1a36b177a..4a01d4d8a 100644 --- a/nettypes.cc +++ b/nettypes.cc @@ -18,6 +18,7 @@ */ # include "nettypes.h" +# include # include using namespace std; @@ -101,6 +102,12 @@ bool prefix_to_slice(const std::vector&dims, { assert(prefix.size() < dims.size()); + // Figure out the width of the slice, given the number of + // prefix numbers there are. We don't need to look at the + // actual values yet, but we do need to know how many there + // are compared to the actual dimensions of the target. So do + // this by multiplying the widths of the dims that are NOT + // accounted for by the prefix or sb indices. size_t acc_wid = 1; vector::const_iterator pcur = dims.end(); for (size_t idx = prefix.size()+1 ; idx < dims.size() ; idx += 1) { @@ -108,8 +115,12 @@ bool prefix_to_slice(const std::vector&dims, acc_wid *= pcur->width(); } - lwid = acc_wid; + lwid = acc_wid; // lwid is now the final slice width. + // pcur is pointing to the dimension AFTER the dimension that + // we have an index for, so step back one, then this will be + // used with the sb index. Start accumulating in the acc_off + // the offset into the n-dimensional vector. -- pcur; if (sb < pcur->get_msb() && sb < pcur->get_lsb()) return false; @@ -122,16 +133,18 @@ bool prefix_to_slice(const std::vector&dims, else acc_off += (pcur->get_lsb() - sb) * acc_wid; + // If there are no more prefix items, we are done. if (prefix.empty()) { loff = acc_off; return true; } - lwid *= pcur->width(); - + // Now similarly go through the prefix numbers, working + // through the dimensions until we run out. Accumulate a + // growing slice width (acc_wid) that is used to caculate the + // growing offset (acc_off). list::const_iterator icur = prefix.end(); do { - -- pcur; -- icur; acc_wid *= pcur->width(); if (pcur->get_msb() >= pcur->get_lsb()) @@ -139,8 +152,11 @@ bool prefix_to_slice(const std::vector&dims, else acc_off += (pcur->get_lsb() - *icur) * acc_wid; + -- pcur; + } while (icur != prefix.begin()); + // Got our final offset. loff = acc_off; return true; diff --git a/parse.y b/parse.y index d9b8f0166..59e526e4e 100644 --- a/parse.y +++ b/parse.y @@ -46,12 +46,8 @@ static ivl_variable_type_t param_active_type = IVL_VT_LOGIC; static struct { NetNet::Type port_net_type; NetNet::PortType port_type; - ivl_variable_type_t var_type; - bool sign_flag; data_type_t* data_type; - list* range; -} port_declaration_context = {NetNet::NONE, NetNet::NOT_A_PORT, - IVL_VT_NO_TYPE, false, 0, 0}; +} port_declaration_context = {NetNet::NONE, NetNet::NOT_A_PORT, 0}; /* The task and function rules need to briefly hold the pointer to the task/function that is currently in progress. */ @@ -417,6 +413,11 @@ static void current_function_set_statement(const YYLTYPE&loc, vector property_qualifier_t property_qualifier; PPackage*package; + struct { + char*text; + data_type_t*type; + } type_identifier; + struct { data_type_t*type; list*exprs; @@ -431,7 +432,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector }; %token IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL -%token TYPE_IDENTIFIER +%token TYPE_IDENTIFIER %token PACKAGE_IDENTIFIER %token DISCIPLINE_IDENTIFIER %token PATHPULSE_IDENTIFIER @@ -730,10 +731,11 @@ class_identifier $$ = tmp; } | TYPE_IDENTIFIER - { class_type_t*tmp = dynamic_cast($1); + { class_type_t*tmp = dynamic_cast($1.type); if (tmp == 0) { - yyerror(@1, "Type name is not a predeclared class name."); + yyerror(@1, "Type name \"%s\"is not a predeclared class name.", $1.text); } + delete[]$1.text; $$ = tmp; } ; @@ -743,13 +745,14 @@ class_identifier does indeed match a name. */ class_declaration_endlabel_opt : ':' TYPE_IDENTIFIER - { class_type_t*tmp = dynamic_cast ($2); + { class_type_t*tmp = dynamic_cast ($2.type); if (tmp == 0) { - yyerror(@2, "error: class declaration endlabel is not a class name\n"); + yyerror(@2, "error: class declaration endlabel \"%s\" is not a class name\n", $2.text); $$ = 0; } else { $$ = strdupnew(tmp->name.str()); } + delete[]$2.text; } | ':' IDENTIFIER { $$ = $2; } @@ -767,12 +770,14 @@ class_declaration_endlabel_opt class_declaration_extends_opt /* IEEE1800-2005: A.1.2 */ : K_extends TYPE_IDENTIFIER - { $$.type = $2; + { $$.type = $2.type; $$.exprs= 0; + delete[]$2.text; } | K_extends TYPE_IDENTIFIER '(' expression_list_with_nuls ')' - { $$.type = $2; + { $$.type = $2.type; $$.exprs = $4; + delete[]$2.text; } | { $$.type = 0; $$.exprs = 0; } @@ -1013,14 +1018,16 @@ data_type /* IEEE1800-2005: A.2.2.1 */ $$ = tmp; } | TYPE_IDENTIFIER dimensions_opt - { if ($2) $$ = new parray_type_t($1, $2); - else $$ = $1; + { if ($2) $$ = new parray_type_t($1.type, $2); + else $$ = $1.type; + delete[]$1.text; } | PACKAGE_IDENTIFIER K_SCOPE_RES { lex_in_package_scope($1); } TYPE_IDENTIFIER { lex_in_package_scope(0); - $$ = $4; + $$ = $4.type; + delete[]$4.text; } | K_string { string_type_t*tmp = new string_type_t; @@ -1307,10 +1314,42 @@ loop_statement /* IEEE1800-2005: A.6.8 */ $$ = tmp; } + // Handle for_variable_declaration syntax by wrapping the for(...) + // statement in a synthetic named block. We can name the block + // after the variable that we are creating, that identifier is + // safe in the controlling scope. | K_for '(' data_type IDENTIFIER '=' expression ';' expression ';' for_step ')' + { static unsigned for_counter = 0; + char for_block_name [64]; + snprintf(for_block_name, sizeof for_block_name, "$ivl_for_loop%u", for_counter); + for_counter += 1; + PBlock*tmp = pform_push_block_scope(for_block_name, PBlock::BL_SEQ); + FILE_NAME(tmp, @1); + current_block_stack.push(tmp); + + listassign_list; + decl_assignment_t*tmp_assign = new decl_assignment_t; + tmp_assign->name = lex_strings.make($4); + assign_list.push_back(tmp_assign); + pform_makewire(@4, 0, str_strength, &assign_list, NetNet::REG, $3); + } statement_or_null - { $$ = 0; - yyerror(@3, "sorry: for_variable_declaration not supported"); + { pform_name_t tmp_hident; + tmp_hident.push_back(name_component_t(lex_strings.make($4))); + + PEIdent*tmp_ident = pform_new_ident(tmp_hident); + FILE_NAME(tmp_ident, @4); + + PForStatement*tmp_for = new PForStatement(tmp_ident, $6, $8, $10, $13); + FILE_NAME(tmp_for, @1); + + pform_pop_scope(); + vectortmp_for_list (1); + tmp_for_list[0] = tmp_for; + PBlock*tmp_blk = current_block_stack.top(); + tmp_blk->set_statement(tmp_for_list); + $$ = tmp_blk; + delete[]$4; } | K_forever statement_or_null @@ -1857,27 +1896,16 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ if ($4 != 0) { yyerror(@4, "internal error: How can there be an unpacked range here?\n"); } - if (port_declaration_context.var_type == IVL_VT_NO_TYPE) { - tmp = pform_make_task_ports(@3, use_port_type, - port_declaration_context.data_type, - ilist); - } else { - tmp = pform_make_task_ports(@3, use_port_type, - port_declaration_context.var_type, - port_declaration_context.sign_flag, - copy_range(port_declaration_context.range), - ilist); - } + tmp = pform_make_task_ports(@3, use_port_type, + port_declaration_context.data_type, + ilist); + } else { // Otherwise, the decorations for this identifier // indicate the type. Save the type for any right // context thta may come later. port_declaration_context.port_type = use_port_type; - port_declaration_context.var_type = IVL_VT_NO_TYPE; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; if ($2 == 0) { $2 = new vector_type_t(IVL_VT_LOGIC, false, 0); FILE_NAME($2, @3); @@ -2143,6 +2171,20 @@ type_declaration delete[]$3; } + /* If the IDENTIFIER already is a typedef, it is possible for this + code to override the definition, but only if the typedef is + inherited from a different scope. */ + | K_typedef data_type TYPE_IDENTIFIER ';' + { perm_string name = lex_strings.make($3.text); + if (pform_test_type_identifier_local(name)) { + yyerror(@3, "error: Typedef identifier \"%s\" is already a type name.", $3.text); + + } else { + pform_set_typedef(name, $2); + } + delete[]$3.text; + } + /* These are forward declarations... */ | K_typedef K_class IDENTIFIER ';' @@ -2170,9 +2212,6 @@ type_declaration delete[]$2; } - | K_typedef data_type TYPE_IDENTIFIER ';' - { yyerror(@3, "error: Typedef identifier is already a type name."); } - | K_typedef error ';' { yyerror(@2, "error: Syntax error in typedef clause."); yyerrok; @@ -3108,9 +3147,10 @@ expr_primary /* There are a few special cases (notably $bits argument) where the expression may be a type name. Let the elaborator sort this out. */ | TYPE_IDENTIFIER - { PETypename*tmp = new PETypename($1); + { PETypename*tmp = new PETypename($1.type); FILE_NAME(tmp,@1); $$ = tmp; + delete[]$1.text; } /* The hierarchy_identifier rule matches simple identifiers as well as @@ -3762,10 +3802,7 @@ list_of_port_declarations pform_module_define_port(@3, name, port_declaration_context.port_type, port_declaration_context.port_net_type, - port_declaration_context.var_type, - port_declaration_context.sign_flag, - port_declaration_context.data_type, - port_declaration_context.range, 0); + port_declaration_context.data_type, 0); delete[]$3; $$ = tmp; } @@ -3785,21 +3822,14 @@ port_declaration : attribute_list_opt K_input net_type_opt data_type_or_implicit IDENTIFIER dimensions_opt { Module::port_t*ptmp; perm_string name = lex_strings.make($5); + data_type_t*use_type = $4; + if ($6) use_type = new uarray_type_t(use_type, $6); ptmp = pform_module_port_reference(name, @2.text, @2.first_line); - pform_module_define_port(@2, name, NetNet::PINPUT, $3, IVL_VT_NO_TYPE, - false, $4, 0, $1); + pform_module_define_port(@2, name, NetNet::PINPUT, $3, use_type, $1); port_declaration_context.port_type = NetNet::PINPUT; port_declaration_context.port_net_type = $3; - port_declaration_context.var_type = IVL_VT_NO_TYPE; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; port_declaration_context.data_type = $4; delete[]$5; - if ($6) { - yyerror(@6, "sorry: Input ports with unpacked dimensions not supported."); - delete $6; - } $$ = ptmp; } | attribute_list_opt @@ -3808,15 +3838,13 @@ port_declaration perm_string name = lex_strings.make($4); ptmp = pform_module_port_reference(name, @2.text, @2.first_line); - pform_module_define_port(@2, name, NetNet::PINPUT, - NetNet::WIRE, IVL_VT_REAL, true, 0, 0, $1); + real_type_t*real_type = new real_type_t(real_type_t::REAL); + FILE_NAME(real_type, @3); + pform_module_define_port(@2, name, NetNet::PINPUT, + NetNet::WIRE, real_type, $1); port_declaration_context.port_type = NetNet::PINPUT; port_declaration_context.port_net_type = NetNet::WIRE; - port_declaration_context.var_type = IVL_VT_REAL; - port_declaration_context.sign_flag = true; - delete port_declaration_context.range; - port_declaration_context.range = 0; - port_declaration_context.data_type = 0; + port_declaration_context.data_type = real_type; delete[]$4; $$ = ptmp; } @@ -3824,14 +3852,9 @@ port_declaration { Module::port_t*ptmp; perm_string name = lex_strings.make($5); ptmp = pform_module_port_reference(name, @2.text, @2.first_line); - pform_module_define_port(@2, name, NetNet::PINOUT, $3, IVL_VT_NO_TYPE, - false, $4, 0, $1); + pform_module_define_port(@2, name, NetNet::PINOUT, $3, $4, $1); port_declaration_context.port_type = NetNet::PINOUT; port_declaration_context.port_net_type = $3; - port_declaration_context.var_type = IVL_VT_NO_TYPE; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; port_declaration_context.data_type = $4; delete[]$5; if ($6) { @@ -3846,21 +3869,21 @@ port_declaration perm_string name = lex_strings.make($4); ptmp = pform_module_port_reference(name, @2.text, @2.first_line); + real_type_t*real_type = new real_type_t(real_type_t::REAL); + FILE_NAME(real_type, @3); pform_module_define_port(@2, name, NetNet::PINOUT, - NetNet::WIRE, IVL_VT_REAL, true, 0, 0, $1); + NetNet::WIRE, real_type, $1); port_declaration_context.port_type = NetNet::PINOUT; port_declaration_context.port_net_type = NetNet::WIRE; - port_declaration_context.var_type = IVL_VT_REAL; - port_declaration_context.sign_flag = true; - delete port_declaration_context.range; - port_declaration_context.range = 0; - port_declaration_context.data_type = 0; + port_declaration_context.data_type = real_type; delete[]$4; $$ = ptmp; } | attribute_list_opt K_output net_type_opt data_type_or_implicit IDENTIFIER dimensions_opt { Module::port_t*ptmp; perm_string name = lex_strings.make($5); + data_type_t*use_dtype = $4; + if ($6) use_dtype = new uarray_type_t(use_dtype, $6); NetNet::Type use_type = $3; if (use_type == NetNet::IMPLICIT) { if (vector_type_t*dtype = dynamic_cast ($4)) { @@ -3882,20 +3905,11 @@ port_declaration } } ptmp = pform_module_port_reference(name, @2.text, @2.first_line); - pform_module_define_port(@2, name, NetNet::POUTPUT, use_type, IVL_VT_NO_TYPE, - false, $4, 0, $1); + pform_module_define_port(@2, name, NetNet::POUTPUT, use_type, use_dtype, $1); port_declaration_context.port_type = NetNet::POUTPUT; port_declaration_context.port_net_type = use_type; - port_declaration_context.var_type = IVL_VT_NO_TYPE; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; port_declaration_context.data_type = $4; delete[]$5; - if ($6) { - yyerror(@6, "sorry: Output ports with unpacked dimensions not supported."); - delete $6; - } $$ = ptmp; } | attribute_list_opt @@ -3904,15 +3918,13 @@ port_declaration perm_string name = lex_strings.make($4); ptmp = pform_module_port_reference(name, @2.text, @2.first_line); + real_type_t*real_type = new real_type_t(real_type_t::REAL); + FILE_NAME(real_type, @3); pform_module_define_port(@2, name, NetNet::POUTPUT, - NetNet::WIRE, IVL_VT_REAL, true, 0, 0, $1); + NetNet::WIRE, real_type, $1); port_declaration_context.port_type = NetNet::POUTPUT; port_declaration_context.port_net_type = NetNet::WIRE; - port_declaration_context.var_type = IVL_VT_REAL; - port_declaration_context.sign_flag = true; - delete port_declaration_context.range; - port_declaration_context.range = 0; - port_declaration_context.data_type = 0; + port_declaration_context.data_type = real_type; delete[]$4; $$ = ptmp; } @@ -3931,14 +3943,9 @@ port_declaration } } ptmp = pform_module_port_reference(name, @2.text, @2.first_line); - pform_module_define_port(@2, name, NetNet::POUTPUT, use_type, IVL_VT_NO_TYPE, - false, $4, 0, $1); + pform_module_define_port(@2, name, NetNet::POUTPUT, use_type, $4, $1); port_declaration_context.port_type = NetNet::PINOUT; port_declaration_context.port_net_type = use_type; - port_declaration_context.var_type = IVL_VT_NO_TYPE; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; port_declaration_context.data_type = $4; pform_make_reginit(@5, name, $7); diff --git a/parse_misc.h b/parse_misc.h index 7887818c0..46a937042 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -96,6 +96,8 @@ extern void lex_in_package_scope(PPackage*pkg); extern data_type_t* pform_test_type_identifier(const char*txt); extern data_type_t* pform_test_type_identifier(PPackage*pkg, const char*txt); +extern bool pform_test_type_identifier_local(perm_string txt); + /* * Test if this identifier is a package name. The pform needs to help * the lexor here because the parser detects packages and saves them. diff --git a/pform.cc b/pform.cc index f2d360521..b8a408b86 100644 --- a/pform.cc +++ b/pform.cc @@ -584,6 +584,31 @@ data_type_t* pform_test_type_identifier(const char*txt) return 0; } +/* + * The parser uses this function to test if the name is a typedef in + * the current scope. We use this to know if we can override the + * definition because it shadows a containing scope. + */ +bool pform_test_type_identifier_local(perm_string name) +{ + if (lexical_scope == 0) { + if (test_type_identifier_in_root(name)) + return true; + else + return false; + } + + LexicalScope*cur_scope = lexical_scope; + + map::iterator cur; + + cur = cur_scope->typedefs.find(name); + if (cur != cur_scope->typedefs.end()) + return true; + + return false; +} + PECallFunction* pform_make_call_function(const struct vlltype&loc, const pform_name_t&name, const list&parms) @@ -2129,15 +2154,14 @@ void pform_make_reginit(const struct vlltype&li, */ void pform_module_define_port(const struct vlltype&li, perm_string name, - NetNet::PortType port_type, + NetNet::PortType port_kind, NetNet::Type type, - ivl_variable_type_t data_type, - bool signed_flag, data_type_t*vtype, - list*range, list*attr) { struct_type_t*struct_type = 0; + ivl_variable_type_t data_type = IVL_VT_NO_TYPE; + bool signed_flag = false; PWire*cur = pform_get_wire_in_scope(name); if (cur) { @@ -2149,27 +2173,34 @@ void pform_module_define_port(const struct vlltype&li, return; } - if (vtype) { - ivl_assert(li, data_type == IVL_VT_NO_TYPE); - ivl_assert(li, range == 0); + // Packed ranges + list*prange = 0; + // Unpacked dimensions + list*urange = 0; + + // If this is an unpacked array, then split out the parts that + // we can send to the PWire object that we create. + if (uarray_type_t*uarr_type = dynamic_cast (vtype)) { + urange = uarr_type->dims.get(); + vtype = uarr_type->base_type; } if (vector_type_t*vec_type = dynamic_cast (vtype)) { data_type = vec_type->base_type; signed_flag = vec_type->signed_flag; - range = vec_type->pdims.get(); + prange = vec_type->pdims.get(); if (vec_type->reg_flag) type = NetNet::REG; } else if (atom2_type_t*atype = dynamic_cast(vtype)) { data_type = IVL_VT_BOOL; signed_flag = atype->signed_flag; - range = make_range_from_width(atype->type_code); + prange = make_range_from_width(atype->type_code); } else if (real_type_t*rtype = dynamic_cast(vtype)) { data_type = IVL_VT_REAL; signed_flag = true; - range = 0; + prange = 0; if (rtype->type_code != real_type_t::REAL) { VLerror(li, "sorry: Only real (not shortreal) supported here (%s:%d).", @@ -2179,7 +2210,7 @@ void pform_module_define_port(const struct vlltype&li, } else if ((struct_type = dynamic_cast(vtype))) { data_type = struct_type->figure_packed_base_type(); signed_flag = false; - range = 0; + prange = 0; } else if (vtype) { VLerror(li, "sorry: Given type %s not supported here (%s:%d).", @@ -2191,7 +2222,7 @@ void pform_module_define_port(const struct vlltype&li, if (data_type == IVL_VT_NO_TYPE) data_type = IVL_VT_LOGIC; - cur = new PWire(name, type, port_type, data_type); + cur = new PWire(name, type, port_kind, data_type); FILE_NAME(cur, li); cur->set_signed(signed_flag); @@ -2199,11 +2230,15 @@ void pform_module_define_port(const struct vlltype&li, if (struct_type) { cur->set_data_type(struct_type); - } else if (range == 0) { + } else if (prange == 0) { cur->set_range_scalar((type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH); } else { - cur->set_range(*range, (type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH); + cur->set_range(*prange, (type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH); + } + + if (urange) { + cur->set_unpacked_idx(*urange); } pform_bind_attributes(cur->attributes, attr); diff --git a/pform.h b/pform.h index 420f437bd..ebe38395d 100644 --- a/pform.h +++ b/pform.h @@ -168,10 +168,7 @@ extern void pform_module_define_port(const struct vlltype&li, perm_string name, NetNet::PortType, NetNet::Type type, - ivl_variable_type_t data_type, - bool signed_flag, data_type_t*vtype, - list*range, list*attr); extern Module::port_t* pform_module_port_reference(perm_string name, diff --git a/t-dll.cc b/t-dll.cc index d28d44c48..a068bb59b 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -160,12 +160,21 @@ inline static const char *basename(ivl_scope_t scope, const char *inst) static perm_string make_scope_name(const hname_t&name) { - if (! name.has_number()) + if (! name.has_numbers()) return name.peek_name(); char buf[1024]; - snprintf(buf, sizeof buf, "%s[%d]", - name.peek_name().str(), name.peek_number()); + snprintf(buf, sizeof buf, "%s", name.peek_name().str()); + + char*cp = buf + strlen(buf); + size_t ncp = sizeof buf - (cp-buf); + + for (size_t idx = 0 ; idx < name.has_numbers() ; idx += 1) { + int len = snprintf(cp, ncp, "[%d]", name.peek_number(idx)); + cp += len; + ncp -= len; + } + return lex_strings.make(buf); }