Correctly handle unpacked array typedefs for ports

If the type of a port is an array type it currently always gets evaluated
in the scope where the port is declared.

But if the type is a typedef it might be declared in a different scope and
must be evaluated in that scope. E.g. the following will declare an array
port with 10 entries and an element type of a 5 bit vector, while it should
declare one with 4 entries and an element type of a 2 bit vector.

```
localparam A = 2;
localparam B = 4;
typedef [A-1:0] T[B];

module test (
  T x
);

localparam A = 5;
localparam B = 10;

endmodule
```

This is in part due to array types being given special handling. This was
necessary before because each base type required slightly different
handling and so the base type had to be extracted from the array type.

This has now been consolidated and all data types are treated the same.
The only exception is the vector type which still needs special handling to
support separate definition of port direction and type.

As a result it is possible to remove the special handling of the array
type. This solves the problem of evaluating the type in the wrong scope.

Some special handling needs to be retained though to be able to
differentiate between array dimensions that are part of a type and array
dimensions that are part of port declaration. This is again necessary to
correctly support separate definition of port direction and type. E.g. in
the example below port `x` and `y` get treated slightly differently, even
though the resulting signals will be identical.

```
typedef logic [7:0] T[1:0];
...
input T x;
input [7:0] y[1:0];
```

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2022-04-11 09:48:29 +02:00
parent fd69d4e09c
commit 2385b32cb3
6 changed files with 27 additions and 66 deletions

View File

@ -33,8 +33,7 @@ PWire::PWire(perm_string n,
: name_(n), type_(t), port_type_(pt), data_type_(dt),
signed_(false),
port_set_(false), net_set_(false), is_scalar_(false),
error_cnt_(0), uarray_type_(0), set_data_type_(0),
discipline_(0)
error_cnt_(0), set_data_type_(0), discipline_(0)
{
switch (rt) {
case SR_PORT:

View File

@ -77,7 +77,6 @@ class PWire : public PNamedItem {
void set_range(const std::list<pform_range_t>&ranges, PWSRType type);
void set_unpacked_idx(const std::list<pform_range_t>&ranges);
void set_uarray_type(uarray_type_t*type) { uarray_type_ = type; }
void set_data_type(data_type_t*type);
@ -121,7 +120,6 @@ class PWire : public PNamedItem {
// If this wire is actually a memory, these indices will give
// me the size and address ranges of the memory.
std::list<pform_range_t>unpacked_;
uarray_type_t*uarray_type_;
// This is the complex type of the wire. the data_type_ may
// modify how this is interpreted.

View File

@ -1003,13 +1003,9 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
unsigned wid = 1;
vector<netrange_t>packed_dimensions;
NetScope*array_type_scope = scope;
if (uarray_type_ && !uarray_type_->name.nil())
array_type_scope = array_type_scope->find_typedef_scope(des, uarray_type_);
NetScope*base_type_scope = array_type_scope;
NetScope *type_scope = scope;
if (set_data_type_ && !set_data_type_->name.nil())
base_type_scope = base_type_scope->find_typedef_scope(des, set_data_type_);
type_scope = type_scope->find_typedef_scope(des, set_data_type_);
des->errors += error_cnt_;
@ -1050,7 +1046,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
cerr << get_fileline() << ": PWire::elaborate_sig: "
<< "Evaluate ranges for net " << basename() << endl;
}
dimensions_ok &= evaluate_ranges(des, base_type_scope, this, nlist, net_);
dimensions_ok &= evaluate_ranges(des, type_scope, this, nlist, net_);
}
assert(net_set_ || net_.empty());
@ -1151,10 +1147,10 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
wtype = NetNet::WIRE;
}
ivl_type_t type = elaborate_type(des, array_type_scope, packed_dimensions);
ivl_type_t type = elaborate_type(des, type_scope, packed_dimensions);
// Create the type for the unpacked dimensions. If the
// unpacked_dimensions are empty this will just return the base type.
type = elaborate_array_type(des, array_type_scope, *this, type, unpacked_);
type = elaborate_array_type(des, type_scope, *this, type, unpacked_);
list<netrange_t> unpacked_dimensions;
// If this is an unpacked array extract the base type and unpacked

33
parse.y
View File

@ -4350,7 +4350,8 @@ list_of_port_declarations
pform_module_define_port(@3, name,
port_declaration_context.port_type,
port_declaration_context.port_net_type,
port_declaration_context.data_type, 0);
port_declaration_context.data_type,
nullptr, nullptr);
delete[]$3;
$$ = tmp;
}
@ -4369,10 +4370,9 @@ port_declaration
: attribute_list_opt K_input net_type_or_var_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(@2, name);
pform_module_define_port(@2, name, NetNet::PINPUT, $3, use_type, $1);
pform_module_define_port(@2, name, NetNet::PINPUT, $3, $4, $6, nullptr,
$1);
port_declaration_context.port_type = NetNet::PINPUT;
port_declaration_context.port_net_type = $3;
port_declaration_context.data_type = $4;
@ -4386,8 +4386,8 @@ port_declaration
ptmp = pform_module_port_reference(@2, name);
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);
pform_module_define_port(@2, name, NetNet::PINPUT, NetNet::WIRE,
real_type, nullptr, $1);
port_declaration_context.port_type = NetNet::PINPUT;
port_declaration_context.port_net_type = NetNet::WIRE;
port_declaration_context.data_type = real_type;
@ -4401,7 +4401,8 @@ port_declaration
data_type_t*use_type = $4;
ptmp = pform_module_port_reference(@2, name);
ptmp->default_value = $7;
pform_module_define_port(@2, name, NetNet::PINPUT, $3, use_type, $1);
pform_module_define_port(@2, name, NetNet::PINPUT, $3, use_type,
nullptr, $1);
port_declaration_context.port_type = NetNet::PINPUT;
port_declaration_context.port_net_type = $3;
port_declaration_context.data_type = $4;
@ -4412,7 +4413,8 @@ port_declaration
{ Module::port_t*ptmp;
perm_string name = lex_strings.make($5);
ptmp = pform_module_port_reference(@2, name);
pform_module_define_port(@2, name, NetNet::PINOUT, $3, $4, $1);
pform_module_define_port(@2, name, NetNet::PINOUT, $3, $4, nullptr,
$1);
port_declaration_context.port_type = NetNet::PINOUT;
port_declaration_context.port_net_type = $3;
port_declaration_context.data_type = $4;
@ -4430,8 +4432,8 @@ port_declaration
ptmp = pform_module_port_reference(@2, name);
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, real_type, $1);
pform_module_define_port(@2, name, NetNet::PINOUT, NetNet::WIRE,
real_type, nullptr, $1);
port_declaration_context.port_type = NetNet::PINOUT;
port_declaration_context.port_net_type = NetNet::WIRE;
port_declaration_context.data_type = real_type;
@ -4441,8 +4443,6 @@ port_declaration
| attribute_list_opt K_output net_type_or_var_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<vector_type_t*> ($4)) {
@ -4460,7 +4460,7 @@ port_declaration
}
}
ptmp = pform_module_port_reference(@2, name);
pform_module_define_port(@2, name, NetNet::POUTPUT, use_type, use_dtype, $1);
pform_module_define_port(@2, name, NetNet::POUTPUT, use_type, $4, $6, $1);
port_declaration_context.port_type = NetNet::POUTPUT;
port_declaration_context.port_net_type = use_type;
port_declaration_context.data_type = $4;
@ -4474,8 +4474,8 @@ port_declaration
ptmp = pform_module_port_reference(@2, name);
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, real_type, $1);
pform_module_define_port(@2, name, NetNet::POUTPUT, NetNet::WIRE,
real_type, nullptr, $1);
port_declaration_context.port_type = NetNet::POUTPUT;
port_declaration_context.port_net_type = NetNet::WIRE;
port_declaration_context.data_type = real_type;
@ -4490,7 +4490,8 @@ port_declaration
use_type = NetNet::IMPLICIT_REG;
}
ptmp = pform_module_port_reference(@2, name);
pform_module_define_port(@2, name, NetNet::POUTPUT, use_type, $4, $1);
pform_module_define_port(@2, name, NetNet::POUTPUT, use_type, $4,
nullptr, $1);
port_declaration_context.port_type = NetNet::POUTPUT;
port_declaration_context.port_net_type = use_type;
port_declaration_context.data_type = $4;

View File

@ -2591,21 +2591,12 @@ void pform_module_define_port(const struct vlltype&li,
NetNet::PortType port_kind,
NetNet::Type type,
data_type_t*vtype,
list<pform_range_t>*urange,
list<named_pexpr_t>*attr,
bool keep_attr)
{
pform_check_net_data_type(li, type, vtype);
// 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;
}
PWire *cur = pform_get_or_make_wire(li, name, type, port_kind, SR_BOTH);
vector_type_t*vec_type = dynamic_cast<vector_type_t*> (vtype);
@ -2616,6 +2607,7 @@ void pform_module_define_port(const struct vlltype&li,
if (urange) {
cur->set_unpacked_idx(*urange);
delete urange;
}
pform_bind_attributes(cur->attributes, attr, keep_attr);
@ -2632,13 +2624,9 @@ void pform_module_define_port(const struct vlltype&li,
; cur != ports->end() ; ++ cur ) {
data_type_t*use_type = vtype;
if (cur->udims)
use_type = new uarray_type_t(vtype, cur->udims);
pform_module_define_port(li, cur->name, port_kind, type, use_type,
attr, true);
if (cur->udims)
delete use_type;
cur->udims, attr, true);
if (cur->expr)
pform_make_var_init(li, cur->name, cur->expr);
@ -2820,12 +2808,6 @@ vector<pform_tf_port_t>*pform_make_task_ports(const struct vlltype&loc,
bool allow_implicit)
{
vector<pform_tf_port_t>*ret = NULL;
std::list<pform_range_t>*unpacked_dims = NULL;
if (uarray_type_t*uarray = dynamic_cast<uarray_type_t*> (vtype)) {
unpacked_dims = uarray->dims.get();
vtype = uarray->base_type;
}
if (vector_type_t*vec_type = dynamic_cast<vector_type_t*> (vtype)) {
ret = pform_make_task_ports_vec(loc, pt, vec_type, ports,
@ -2834,14 +2816,6 @@ vector<pform_tf_port_t>*pform_make_task_ports(const struct vlltype&loc,
ret = do_make_task_ports(loc, pt, vtype, ports);
}
if (unpacked_dims) {
for (list<pform_port_t>::iterator cur = ports->begin()
; cur != ports->end() ; ++ cur ) {
PWire*wire = pform_get_wire_in_scope(cur->name);
wire->set_unpacked_idx(*unpacked_dims);
}
}
delete ports;
return ret;
}
@ -3213,10 +3187,6 @@ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type,
assert(0);
}
uarray_type_t*uarray_type = dynamic_cast<uarray_type_t*> (data_type);
if (uarray_type)
data_type = uarray_type->base_type;
vector_type_t*vec_type = dynamic_cast<vector_type_t*> (data_type);
for (std::vector<PWire*>::iterator it= wires->begin();
@ -3230,10 +3200,6 @@ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type,
bool rc = wire->set_wire_type(net_type);
ivl_assert(li, rc);
if (uarray_type) {
wire->set_unpacked_idx(*uarray_type->dims.get());
wire->set_uarray_type(uarray_type);
}
wire->set_data_type(data_type);
pform_bind_attributes(wire->attributes, attr, true);

View File

@ -154,6 +154,7 @@ extern void pform_module_define_port(const struct vlltype&li,
NetNet::PortType,
NetNet::Type type,
data_type_t*vtype,
std::list<pform_range_t>*urange,
std::list<named_pexpr_t>*attr,
bool keep_attr =false);
extern void pform_module_define_port(const struct vlltype&li,