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.
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;

View File

@ -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;
};

View File

@ -2585,6 +2585,7 @@ bool PEIdent::calculate_packed_indices_(Design*des, NetScope*scope, NetNet*net,
{
list<index_component_t> 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();

View File

@ -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<long> unpacked_indices_const;
@ -590,13 +594,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 +649,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 +662,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<NetEConst*>(canon_index);
ivl_assert(*this, canon_const);
widx = canon_const->value().as_long();
widx_flag = true;
delete canon_index;
}
}
@ -717,7 +742,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
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 +754,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 +883,20 @@ 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()) {
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
select of the signal that attaches to the port. Also handle
range and direction checking here. */
@ -912,6 +958,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);

View File

@ -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,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,
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
{ 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, $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_net_type = $3;
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

View File

@ -2173,24 +2173,34 @@ void pform_module_define_port(const struct vlltype&li,
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)) {
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<atom2_type_t*>(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<real_type_t*>(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).",
@ -2200,7 +2210,7 @@ void pform_module_define_port(const struct vlltype&li,
} else if ((struct_type = dynamic_cast<struct_type_t*>(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).",
@ -2220,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);