From fc1f9ac6a54079822ea2f58a4dd932b570c62ef7 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 22 Mar 2014 20:50:47 -0700 Subject: [PATCH] Handle unpacked arrays as module input ports. --- elab_expr.cc | 2 +- elab_net.cc | 19 ++++++++++++++++--- elaborate.cc | 50 +++++++++++++++++++++++++++++++++++--------------- netmisc.cc | 18 ++++++++++++++++++ netmisc.h | 4 ++++ 5 files changed, 74 insertions(+), 19 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index 0d9b82847..179ec1bce 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -3970,7 +3970,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; } diff --git a/elab_net.cc b/elab_net.cc index ad7adf138..7270a8aff 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -890,13 +890,26 @@ NetNet* PEIdent::elaborate_subport(Design*des, NetScope*scope) const << ", port_type()=" << sig->port_type() << endl; } - if (sig->unpacked_dimensions()) { - cerr << get_fileline() << ": sorry: " - << "Don't know now to elaborate unpacked array ports." << 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. */ diff --git a/elaborate.cc b/elaborate.cc index 64925639e..9ed0d089b 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -228,15 +228,7 @@ void PGAssign::elaborate_unpacked_array_(Design*des, NetScope*scope, NetNet*lval ivl_assert(*this, rval_net->pin_count() == lval->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(*this); - des->add_node(driver); - - connect(lval->pin(idx), driver->pin(0)); - connect(driver->pin(1), rval_net->pin(idx)); - } + assign_unpacked_with_bufz(des, scope, this, lval, rval_net); } unsigned PGBuiltin::calculate_array_count_(Design*des, NetScope*scope, @@ -1378,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 ); @@ -1420,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 @@ -1499,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. @@ -1555,6 +1570,9 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const } else { + // For now, do not support unpacked array outputs. + ivl_assert(*this, prts[0]->unpacked_dimensions()==0); + /* Port type must be OUTPUT here. */ ivl_assert(*this, prts[0]->port_type() == NetNet::POUTPUT); @@ -5840,7 +5858,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/netmisc.cc b/netmisc.cc index 91c974184..2beb1aa5f 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -1338,3 +1338,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