First pass at support for continuous assign of unpacked net arrays.
This commit is contained in:
parent
751f19cc46
commit
6caa41cc93
5
PExpr.h
5
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;
|
||||
|
|
|
|||
1
PGate.h
1
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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
64
elab_net.cc
64
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<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);
|
||||
|
|
|
|||
32
elaborate.cc
32
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,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
|
||||
{
|
||||
|
|
|
|||
8
parse.y
8
parse.y
|
|
@ -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
|
||||
|
|
|
|||
28
pform.cc
28
pform.cc
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue