First pass at support for continuous assign of unpacked net arrays.

This commit is contained in:
Stephen Williams 2014-03-16 17:08:38 -07:00
parent 751f19cc46
commit 6caa41cc93
7 changed files with 123 additions and 16 deletions

View File

@ -366,6 +366,11 @@ class PEIdent : public PExpr {
// only applies to Ident expressions. // only applies to Ident expressions.
NetNet* elaborate_subport(Design*des, NetScope*sc) const; 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; verinum* eval_const(Design*des, NetScope*sc) const;
virtual bool is_collapsible_net(Design*des, NetScope*scope) const; virtual bool is_collapsible_net(Design*des, NetScope*scope) const;

View File

@ -124,6 +124,7 @@ class PGAssign : public PGate {
virtual bool elaborate_sig(Design*des, NetScope*scope) const; virtual bool elaborate_sig(Design*des, NetScope*scope) const;
private: private:
void elaborate_unpacked_array_(Design*des, NetScope*scope, NetNet*lval) const;
}; };

View File

@ -2585,6 +2585,7 @@ bool PEIdent::calculate_packed_indices_(Design*des, NetScope*scope, NetNet*net,
{ {
list<index_component_t> index; list<index_component_t> index;
index = path_.back().index; index = path_.back().index;
ivl_assert(*this, index.size() >= net->unpacked_dimensions());
for (size_t idx = 0 ; idx < net->unpacked_dimensions() ; idx += 1) for (size_t idx = 0 ; idx < net->unpacked_dimensions() ; idx += 1)
index.pop_front(); index.pop_front();

View File

@ -501,6 +501,10 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
unsigned midx = sig->vector_width()-1, lidx = 0; unsigned midx = sig->vector_width()-1, lidx = 0;
// The default word select is the first. // The default word select is the first.
long widx = 0; 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<long> unpacked_indices_const; list<long> unpacked_indices_const;
@ -590,13 +594,31 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
midx = lidx + tmp_wid - 1; 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) { } else if (sig->unpacked_dimensions() > 0) {
// Make sure there are enough indices to address an array element. // Make sure there are enough indices to address an array element.
if (path_tail.index.size() < sig->unpacked_dimensions()) { if (path_tail.index.size() < sig->unpacked_dimensions()) {
cerr << get_fileline() << ": error: Array " << path() cerr << get_fileline() << ": error: Array " << path()
<< " needs " << sig->unpacked_dimensions() << " indices," << " 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; des->errors += 1;
return 0; return 0;
} }
@ -627,6 +649,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
<< sig->name() << as_indices(unpacked_indices) << sig->name() << as_indices(unpacked_indices)
<< "." << endl; << "." << endl;
widx = -1; widx = -1;
widx_flag = true;
} else { } else {
NetExpr*canon_index = 0; NetExpr*canon_index = 0;
@ -639,12 +662,14 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
<< sig->name() << as_indices(unpacked_indices_const) << sig->name() << as_indices(unpacked_indices_const)
<< "." << endl; << "." << endl;
widx = -1; widx = -1;
widx_flag = true;
} else { } else {
NetEConst*canon_const = dynamic_cast<NetEConst*>(canon_index); NetEConst*canon_const = dynamic_cast<NetEConst*>(canon_index);
ivl_assert(*this, canon_const); ivl_assert(*this, canon_const);
widx = canon_const->value().as_long(); widx = canon_const->value().as_long();
widx_flag = true;
delete canon_index; delete canon_index;
} }
} }
@ -717,7 +742,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
return 0; return 0;
} }
if (sig->pin_count() > 1) { if (sig->pin_count() > 1 && widx_flag) {
if (widx < 0 || widx >= (long) sig->pin_count()) if (widx < 0 || widx >= (long) sig->pin_count())
return 0; return 0;
@ -729,6 +754,13 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
tmp->local_flag(true); tmp->local_flag(true);
connect(sig->pin(widx), tmp->pin(0)); connect(sig->pin(widx), tmp->pin(0));
sig = tmp; 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 /* If the desired l-value vector is narrower than the
@ -851,6 +883,20 @@ NetNet* PEIdent::elaborate_subport(Design*des, NetScope*scope) const
long midx; long midx;
long lidx; 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()) {
cerr << get_fileline() << ": sorry: "
<< "Don't know now to elaborate unpacked array ports." << endl;
des->errors += 1;
return 0;
}
/* Evaluate the part/bit select expressions, to get the part /* Evaluate the part/bit select expressions, to get the part
select of the signal that attaches to the port. Also handle select of the signal that attaches to the port. Also handle
range and direction checking here. */ range and direction checking here. */
@ -912,6 +958,20 @@ NetNet* PEIdent::elaborate_subport(Design*des, NetScope*scope) const
return sig; 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 bool PEIdent::is_collapsible_net(Design*des, NetScope*scope) const
{ {
assert(scope); assert(scope);

View File

@ -77,11 +77,19 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
return; 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); ivl_assert(*this, lval->pin_count() == 1);
if (debug_elaborate) { if (debug_elaborate) {
cerr << get_fileline() << ": debug: PGAssign: elaborated l-value" cerr << get_fileline() << ": PGAssign::elaborate: elaborated l-value"
<< " width=" << lval->vector_width() << endl; << " width=" << lval->vector_width()
<< ", pin_count=" << lval->pin_count() << endl;
} }
NetExpr*rval_expr = elaborate_rval_expr(des, scope, lval->net_type(), NetExpr*rval_expr = elaborate_rval_expr(des, scope, lval->net_type(),
@ -211,6 +219,26 @@ 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<PEIdent*> (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());
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));
}
}
unsigned PGBuiltin::calculate_array_count_(Design*des, NetScope*scope, unsigned PGBuiltin::calculate_array_count_(Design*des, NetScope*scope,
long&high, long&low) const long&high, long&low) const
{ {

View File

@ -3822,16 +3822,14 @@ port_declaration
: attribute_list_opt K_input net_type_opt data_type_or_implicit IDENTIFIER dimensions_opt : attribute_list_opt K_input net_type_opt data_type_or_implicit IDENTIFIER dimensions_opt
{ Module::port_t*ptmp; { Module::port_t*ptmp;
perm_string name = lex_strings.make($5); 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); ptmp = pform_module_port_reference(name, @2.text, @2.first_line);
pform_module_define_port(@2, name, NetNet::PINPUT, $3, $4, $1); pform_module_define_port(@2, name, NetNet::PINPUT, $3, use_type, $1);
port_declaration_context.port_type = NetNet::PINPUT; port_declaration_context.port_type = NetNet::PINPUT;
port_declaration_context.port_net_type = $3; port_declaration_context.port_net_type = $3;
port_declaration_context.data_type = $4; port_declaration_context.data_type = $4;
delete[]$5; delete[]$5;
if ($6) {
yyerror(@6, "sorry: Input ports with unpacked dimensions not supported.");
delete $6;
}
$$ = ptmp; $$ = ptmp;
} }
| attribute_list_opt | attribute_list_opt

View File

@ -2173,24 +2173,34 @@ void pform_module_define_port(const struct vlltype&li,
return; return;
} }
list<pform_range_t>*range = 0; // Packed ranges
list<pform_range_t>*prange = 0;
// Unpacked dimensions
list<pform_range_t>*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<uarray_type_t*> (vtype)) {
urange = uarr_type->dims.get();
vtype = uarr_type->base_type;
}
if (vector_type_t*vec_type = dynamic_cast<vector_type_t*> (vtype)) { if (vector_type_t*vec_type = dynamic_cast<vector_type_t*> (vtype)) {
data_type = vec_type->base_type; data_type = vec_type->base_type;
signed_flag = vec_type->signed_flag; signed_flag = vec_type->signed_flag;
range = vec_type->pdims.get(); prange = vec_type->pdims.get();
if (vec_type->reg_flag) if (vec_type->reg_flag)
type = NetNet::REG; type = NetNet::REG;
} else if (atom2_type_t*atype = dynamic_cast<atom2_type_t*>(vtype)) { } else if (atom2_type_t*atype = dynamic_cast<atom2_type_t*>(vtype)) {
data_type = IVL_VT_BOOL; data_type = IVL_VT_BOOL;
signed_flag = atype->signed_flag; 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<real_type_t*>(vtype)) { } else if (real_type_t*rtype = dynamic_cast<real_type_t*>(vtype)) {
data_type = IVL_VT_REAL; data_type = IVL_VT_REAL;
signed_flag = true; signed_flag = true;
range = 0; prange = 0;
if (rtype->type_code != real_type_t::REAL) { if (rtype->type_code != real_type_t::REAL) {
VLerror(li, "sorry: Only real (not shortreal) supported here (%s:%d).", VLerror(li, "sorry: Only real (not shortreal) supported here (%s:%d).",
@ -2200,7 +2210,7 @@ void pform_module_define_port(const struct vlltype&li,
} else if ((struct_type = dynamic_cast<struct_type_t*>(vtype))) { } else if ((struct_type = dynamic_cast<struct_type_t*>(vtype))) {
data_type = struct_type->figure_packed_base_type(); data_type = struct_type->figure_packed_base_type();
signed_flag = false; signed_flag = false;
range = 0; prange = 0;
} else if (vtype) { } else if (vtype) {
VLerror(li, "sorry: Given type %s not supported here (%s:%d).", VLerror(li, "sorry: Given type %s not supported here (%s:%d).",
@ -2220,11 +2230,15 @@ void pform_module_define_port(const struct vlltype&li,
if (struct_type) { if (struct_type) {
cur->set_data_type(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); cur->set_range_scalar((type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH);
} else { } 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); pform_bind_attributes(cur->attributes, attr);