Prevent invalid port redeclaration

(System)Verilog allows to declare the port direction separate from the
signal declaration. E.g.

```
output x;
integer x;
```

But this is only allowed if the port declaration
 * does not have an explicit net type
 * does not have an explicit data type
 * is a non-ANSI style declaration

For all other cases of port declarations the signal is considered fully
defined and it is not allowed to have a separate signal declaration.

In addition the declared packed dimensions need to match between the port
and signal declaration.

In the current implementation there are a few cases where this is not
handled correctly.

1) It is possible to declare non-ANSI task ports with the same name over
and over again, if it was declared as a signal before the port.

```
task t;
  string x;
  input logic x;
  output real x;
endtask
```

2) It is possible to re-declare non-ANSI input ports of a module that have
a data type, but no explicit net type.

```
module M;
  input integer x;
  wire integer x;
endmodule
```

3) It is possible to re-declare a ANSI port if it has an implicit data type.

```
module M(output [1:0] x);
  reg [1:0] x;
endmodule
```

4) It is possible to declare a vector signal for a scalar non-ANSI task
port.

```
task t;
input x;
reg [7:0] x;
```

To handle all of these correctly refactor signal declaration and lookup a
bit.

The PWire class that represents a signal already has two flags `port_set_`
and `net_set_`. These flags indicate whether a signal has already been used
in a port or signal declaration. A port declaration that includes an
explicit data type is considered both a port and signal declaration.

Use these flags to decide whether it is possible to extend an existing
declaration. E.g. when creating a port without an explicit data type and a
PWire by that name already exists and the `port_set_` flag is not set
extend the existing PWire. On the other hand if the `port_set_` flag is
already set report an error.

Similar for signals but with the `net_set_` flag.

For port declarations with an explicit data type or ANSI style port
declarations it is always an error if a PWire by that name already exists.

This is for both module and task/function ports.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2022-03-13 09:50:52 +01:00
parent 7fbfd82d51
commit 6204b78610
9 changed files with 160 additions and 252 deletions

View File

@ -436,7 +436,6 @@ void PEIdent::declare_implicit_nets(LexicalScope*scope, NetNet::Type type)
PWire*net = new PWire(name, type, NetNet::NOT_A_PORT, IVL_VT_LOGIC);
net->set_file(get_file());
net->set_lineno(get_lineno());
net->set_range_scalar(SR_NET);
scope->wires[name] = net;
if (warn_implicit) {
cerr << get_fileline() << ": warning: implicit "

122
PWire.cc
View File

@ -18,6 +18,7 @@
*/
# include "config.h"
# include "ivl_assert.h"
# include "PWire.h"
# include "PExpr.h"
# include <cassert>
@ -27,13 +28,26 @@ using namespace std;
PWire::PWire(perm_string n,
NetNet::Type t,
NetNet::PortType pt,
ivl_variable_type_t dt)
ivl_variable_type_t dt,
PWSRType rt)
: 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)
{
switch (rt) {
case SR_PORT:
port_set_ = true;
break;
case SR_NET:
net_set_ = true;
break;
case SR_BOTH:
port_set_ = true;
net_set_ = true;
break;
}
}
NetNet::Type PWire::get_wire_type() const
@ -132,47 +146,23 @@ bool PWire::get_signed() const
return signed_;
}
void PWire::set_range_scalar(PWSRType type)
void PWire::set_port(NetNet::PortType pt)
{
is_scalar_ = true;
switch (type) {
case SR_PORT:
if (port_set_) {
cerr << get_fileline() << ": error: Port ``" << name_
<< "'' has already been declared a port." << endl;
error_cnt_ += 1;
} else {
port_set_ = true;
}
return;
ivl_assert(*this, !port_set_);
port_set_ = true;
case SR_NET:
if (net_set_) {
cerr << get_fileline() << ": error: Net ``" << name_
<< "'' has already been declared." << endl;
error_cnt_ += 1;
} else {
net_set_ = true;
}
return;
bool rc = set_port_type(pt);
ivl_assert(*this, rc);
}
case SR_BOTH:
if (port_set_ || net_set_) {
if (port_set_) {
cerr << get_fileline() << ": error: Port ``" << name_
<< "'' has already been declared a port." << endl;
error_cnt_ += 1;
}
if (net_set_) {
cerr << get_fileline() << ": error: Net ``" << name_
<< "'' has already been declared." << endl;
error_cnt_ += 1;
}
} else {
port_set_ = true;
net_set_ = true;
}
return;
void PWire::set_net(NetNet::Type t)
{
ivl_assert(*this, !net_set_);
net_set_ = true;
if (t != NetNet::IMPLICIT) {
bool rc = set_wire_type(t);
ivl_assert(*this, rc);
}
}
@ -180,49 +170,21 @@ void PWire::set_range(const list<pform_range_t>&rlist, PWSRType type)
{
switch (type) {
case SR_PORT:
if (port_set_) {
cerr << get_fileline() << ": error: Port ``" << name_
<< "'' has already been declared a port." << endl;
error_cnt_ += 1;
} else {
port_ = rlist;
port_set_ = true;
is_scalar_ = false;
}
return;
if (!port_.empty())
return;
port_ = rlist;
break;
case SR_NET:
if (net_set_) {
cerr << get_fileline() << ": error: Net ``" << name_
<< "'' has already been declared." << endl;
error_cnt_ += 1;
} else {
net_ = rlist;
net_set_ = true;
is_scalar_ = false;
}
return;
if (!net_.empty())
return;
net_ = rlist;
break;
case SR_BOTH:
if (port_set_ || net_set_) {
if (port_set_) {
cerr << get_fileline() << ": error: Port ``" << name_
<< "'' has already been declared a port." << endl;
error_cnt_ += 1;
}
if (net_set_) {
cerr << get_fileline() << ": error: Net ``" << name_
<< "'' has already been declared." << endl;
error_cnt_ += 1;
}
} else {
port_ = rlist;
port_set_ = true;
net_ = rlist;
net_set_ = true;
is_scalar_ = false;
}
return;
if (!port_.empty() || !net_.empty())
return;
port_ = rlist;
net_ = rlist;
break;
}
}

View File

@ -57,7 +57,8 @@ class PWire : public PNamedItem {
PWire(perm_string name,
NetNet::Type t,
NetNet::PortType pt,
ivl_variable_type_t dt);
ivl_variable_type_t dt,
PWSRType rt = SR_NET);
// Return a hierarchical name.
perm_string basename() const;
@ -74,7 +75,6 @@ class PWire : public PNamedItem {
bool set_data_type(ivl_variable_type_t dt);
ivl_variable_type_t get_data_type() const;
void set_range_scalar(PWSRType type);
void set_range(const std::list<pform_range_t>&ranges, PWSRType type);
void set_unpacked_idx(const std::list<pform_range_t>&ranges);
@ -94,6 +94,11 @@ class PWire : public PNamedItem {
SymbolType symbol_type() const;
bool is_net() const { return net_set_; };
bool is_port() const { return port_set_; };
void set_net(NetNet::Type t);
void set_port(NetNet::PortType pt);
private:
perm_string name_;
NetNet::Type type_;

View File

@ -1040,8 +1040,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
<< "Evaluate ranges for port " << basename() << endl;
}
dimensions_ok &= evaluate_ranges(des, scope, this, plist, port_);
nlist = plist;
/* An implicit port can have a range so note that here. */
}
assert(port_set_ || port_.empty());
@ -1062,9 +1060,10 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
<< ". Now check for consistency." << endl;
}
/* We have a port size error */
if (port_set_ && net_set_ && !test_ranges_eeq(plist, nlist)) {
/* We have a port size error. Skip this if the dimensions could not
* be evaluated since it will likely print nonsensical errors. */
if (port_set_ && net_set_ && !test_ranges_eeq(plist, nlist) &&
dimensions_ok) {
/* Scalar port with a vector net/etc. definition */
if (port_.empty()) {
if (!gn_io_range_error_flag) {
@ -1103,7 +1102,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
}
}
packed_dimensions = nlist;
packed_dimensions = net_set_ ? nlist : plist;
wid = netrange_width(packed_dimensions);
if (wid > warn_dimension_size) {
cerr << get_fileline() << ": warning: Vector size "
@ -1116,17 +1115,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
attrib_list_t*attrib_list = evaluate_attributes(attributes, nattrib,
des, scope);
if (data_type_ == IVL_VT_REAL && !packed_dimensions.empty()) {
cerr << get_fileline() << ": error: real ";
if (wtype == NetNet::REG) cerr << "variable";
else cerr << "net";
cerr << " '" << name_
<< "' cannot be declared as a vector, found a range "
<< packed_dimensions << "." << endl;
des->errors += 1;
return 0;
}
/* If the net type is supply0 or supply1, replace it
with a simple wire with a pulldown/pullup with supply
strength. In other words, transform:

View File

@ -1,23 +1,23 @@
./ivltests/pr1723367.v:131: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:138: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:132: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:140: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:141: warning: Scalar port ``b'' has a vectored net declaration [15:0].
./ivltests/pr1723367.v:148: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:156: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:167: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:174: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:149: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:157: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:168: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:176: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:177: warning: Scalar port ``b'' has a vectored net declaration [15:0].
./ivltests/pr1723367.v:184: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:192: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:203: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:212: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:185: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:193: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:204: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:214: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:215: warning: Scalar port ``b'' has a vectored net declaration [31:0].
./ivltests/pr1723367.v:246: warning: Scalar port ``a'' has a vectored net declaration [15:0].
./ivltests/pr1723367.v:253: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:247: warning: Scalar port ``a'' has a vectored net declaration [15:0].
./ivltests/pr1723367.v:255: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:256: warning: Scalar port ``b'' has a vectored net declaration [31:0].
./ivltests/pr1723367.v:282: warning: Scalar port ``a'' has a vectored net declaration [15:0].
./ivltests/pr1723367.v:289: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:283: warning: Scalar port ``a'' has a vectored net declaration [15:0].
./ivltests/pr1723367.v:291: warning: Scalar port ``a'' has a vectored net declaration [7:0].
./ivltests/pr1723367.v:292: warning: Scalar port ``b'' has a vectored net declaration [15:0].
./ivltests/pr1723367.v:307: warning: Scalar port ``a'' has a vectored net declaration [15:0].
./ivltests/pr1723367.v:308: warning: Scalar port ``a'' has a vectored net declaration [15:0].
sum[ 1] = 0101010101100000
sum[ 2] = 0101010101100000
sum[ 3] = 0101010101100000

View File

@ -1 +1,2 @@
./ivltests/pr1841300.v:15: warning: Scalar port ``l'' has a vectored net declaration [4:0].
a is '14'; b is 'fffffff4'; c is 'fffffff4'

View File

@ -1 +1,8 @@
./ivltests/pr1960619.v:26: warning: Scalar port ``l'' has a vectored net declaration [7:0].
./ivltests/pr1960619.v:26: warning: Scalar port ``r'' has a vectored net declaration [7:0].
./ivltests/pr1960619.v:14: warning: Scalar port ``l'' has a vectored net declaration [4:0].
./ivltests/pr1960619.v:32: warning: Scalar port ``l'' has a vectored net declaration [31:0].
./ivltests/pr1960619.v:47: warning: Scalar port ``l'' has a vectored net declaration [31:0].
./ivltests/pr1960619.v:20: warning: Scalar port ``l'' has a vectored net declaration [7:0].
./ivltests/pr1960619.v:20: warning: Scalar port ``r'' has a vectored net declaration [7:0].
a is 14; b is fffffff4; c is 14; d is fffffff4

View File

@ -1,3 +1,5 @@
./ivltests/pr2001162.v:36: warning: Scalar port ``l'' has a vectored net declaration [31:0].
./ivltests/pr2001162.v:36: warning: Scalar port ``r'' has a vectored net declaration [31:0].
test2 increment; reading counter as 0
test1 increment; reading counter as 1
test2 increment; reading counter as 2

218
pform.cc
View File

@ -2148,13 +2148,8 @@ static void pform_set_net_range(PWire *wire,
PWSRType rt = SR_NET,
std::list<named_pexpr_t>*attr = 0)
{
if (range == 0) {
/* This is the special case that we really mean a
scalar. Set a fake range. */
wire->set_range_scalar(rt);
} else {
if (range)
wire->set_range(*range, rt);
}
wire->set_signed(signed_flag);
pform_bind_attributes(wire->attributes, attr, true);
@ -2515,6 +2510,68 @@ void pform_make_var_init(const struct vlltype&li,
lexical_scope->var_inits.push_back(ass);
}
/*
* This function makes a single signal (a wire, a reg, etc) as
* requested by the parser. The name is unscoped, so I attach the
* current scope to it (with the scoped_name function) and I try to
* resolve it with an existing PWire in the scope.
*
* The wire might already exist because of an implicit declaration in
* a module port, i.e.:
*
* module foo (bar...
*
* reg bar;
*
* The output (or other port direction indicator) may or may not have
* been seen already, so I do not do any checking with it yet. But I
* do check to see if the name has already been declared, as this
* function is called for every declaration.
*/
static PWire* pform_get_or_make_wire(const struct vlltype&li, perm_string name,
NetNet::Type type, NetNet::PortType ptype,
ivl_variable_type_t dtype, PWSRType rt)
{
PWire *cur = 0;
// If this is not a full declaration check if there is already a signal
// with the same name that can be extended.
if (rt != SR_BOTH)
cur = pform_get_wire_in_scope(name);
// If the wire already exists but isn't yet fully defined,
// carry on adding details.
if (rt == SR_NET && cur && !cur->is_net()) {
// At the moment there can only be one location for the PWire, if
// there is both a port and signal declaration use the location of
// the signal.
FILE_NAME(cur, li);
cur->set_net(type);
return cur;
}
if (rt == SR_PORT && cur && !cur->is_port()) {
cur->set_port(ptype);
return cur;
}
// If the wire already exists and is fully defined, this
// must be a redeclaration. Start again with a new wire.
// The error will be reported when we add the new wire
// to the scope. Do not delete the old wire - it will
// remain in the local symbol map.
cur = new PWire(name, type, ptype, dtype, rt);
FILE_NAME(cur, li);
pform_put_wire_in_scope(name, cur);
return cur;
}
/*
* This function is used by the parser when I have port definition of
* the form like this:
@ -2536,16 +2593,6 @@ void pform_module_define_port(const struct vlltype&li,
ivl_variable_type_t data_type = IVL_VT_NO_TYPE;
bool signed_flag = false;
PWire*cur = pform_get_wire_in_scope(name);
if (cur) {
ostringstream msg;
msg << name << " definition conflicts with "
<< "definition at " << cur->get_fileline()
<< ".";
VLerror(msg.str().c_str());
return;
}
pform_check_net_data_type(li, type, vtype);
// Packed ranges
@ -2583,27 +2630,22 @@ void pform_module_define_port(const struct vlltype&li,
if (data_type == IVL_VT_NO_TYPE)
data_type = IVL_VT_LOGIC;
cur = new PWire(name, type, port_kind, data_type);
FILE_NAME(cur, li);
PWire *cur = pform_get_or_make_wire(li, name, type, port_kind, data_type,
SR_BOTH);
cur->set_signed(signed_flag);
if (vtype)
cur->set_data_type(vtype);
if (prange == 0) {
cur->set_range_scalar((type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH);
} else {
cur->set_range(*prange, (type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH);
}
if (prange)
cur->set_range(*prange, SR_BOTH);
if (urange) {
cur->set_unpacked_idx(*urange);
}
pform_bind_attributes(cur->attributes, attr, keep_attr);
pform_put_wire_in_scope(name, cur);
}
void pform_module_define_port(const struct vlltype&li,
@ -2633,66 +2675,6 @@ void pform_module_define_port(const struct vlltype&li,
delete attr;
}
/*
* This function makes a single signal (a wire, a reg, etc) as
* requested by the parser. The name is unscoped, so I attach the
* current scope to it (with the scoped_name function) and I try to
* resolve it with an existing PWire in the scope.
*
* The wire might already exist because of an implicit declaration in
* a module port, i.e.:
*
* module foo (bar...
*
* reg bar;
*
* The output (or other port direction indicator) may or may not have
* been seen already, so I do not do any checking with it yet. But I
* do check to see if the name has already been declared, as this
* function is called for every declaration.
*/
static PWire* pform_get_or_make_wire(const vlltype&li, perm_string name,
NetNet::Type type, NetNet::PortType ptype,
ivl_variable_type_t dtype)
{
PWire*cur = pform_get_wire_in_scope(name);
// If the wire already exists but isn't yet fully defined,
// carry on adding details.
if (cur && (cur->get_data_type() == IVL_VT_NO_TYPE ||
cur->get_wire_type() == NetNet::IMPLICIT) ) {
// If this is not implicit ("implicit" meaning we don't
// know what the type is yet) then set the type now.
if (type != NetNet::IMPLICIT) {
bool rc = cur->set_wire_type(type);
if (rc == false) {
ostringstream msg;
msg << name << " " << type
<< " definition conflicts with " << cur->get_wire_type()
<< " definition at " << cur->get_fileline()
<< ".";
VLerror(msg.str().c_str());
}
FILE_NAME(cur, li);
}
return cur;
}
// If the wire already exists and is fully defined, this
// must be a redeclaration. Start again with a new wire.
// The error will be reported when we add the new wire
// to the scope. Do not delete the old wire - it will
// remain in the local symbol map.
cur = new PWire(name, type, ptype, dtype);
FILE_NAME(cur, li);
pform_put_wire_in_scope(name, cur);
return cur;
}
/*
* this is the basic form of pform_makewire. This takes a single simple
* name, port type, net type, data type, and attributes, and creates
@ -2703,7 +2685,7 @@ PWire *pform_makewire(const vlltype&li, perm_string name, NetNet::Type type,
ivl_variable_type_t dt, std::list<pform_range_t> *indices)
{
PWire*cur = pform_get_or_make_wire(li, name, type, NetNet::NOT_A_PORT,
dt);
dt, SR_NET);
assert(cur);
bool flag;
@ -2717,7 +2699,6 @@ PWire *pform_makewire(const vlltype&li, perm_string name, NetNet::Type type,
<< " to " << dt << "." << endl;
}
ivl_assert(*cur, flag);
cur->set_range_scalar(SR_NET);
cur->set_signed(true);
break;
default:
@ -2821,27 +2802,21 @@ static vector<pform_tf_port_t>*pform_make_task_ports(const struct vlltype&loc,
assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT);
assert(ports);
vector<pform_tf_port_t>*res = new vector<pform_tf_port_t>(0);
PWSRType rt = vtype != IVL_VT_NO_TYPE ? SR_BOTH : SR_PORT;
for (list<pform_port_t>::iterator cur = ports->begin()
; cur != ports->end() ; ++ cur ) {
perm_string &name = cur->name;
/* Look for a preexisting wire. If it exists, set the
port direction. If not, create it. */
PWire*curw = pform_get_wire_in_scope(name);
if (curw) {
curw->set_port_type(pt);
} else {
curw = new PWire(name, NetNet::IMPLICIT_REG, pt, vtype);
FILE_NAME(curw, loc);
pform_put_wire_in_scope(name, curw);
}
PWire*curw = pform_get_or_make_wire(loc, name, NetNet::IMPLICIT_REG,
pt, vtype, rt);
curw->set_signed(signed_flag);
/* If there is a range involved, it needs to be set. */
if (range) {
curw->set_range(*range, SR_PORT);
}
if (range)
curw->set_range(*range, rt);
if (cur->udims) {
if (pform_requires_sv(loc, "Task/function port with unpacked dimensions"))
@ -2857,27 +2832,23 @@ static vector<pform_tf_port_t>*pform_make_task_ports(const struct vlltype&loc,
static vector<pform_tf_port_t>*do_make_task_ports(const struct vlltype&loc,
NetNet::PortType pt,
ivl_variable_type_t var_type,
ivl_variable_type_t vtype,
data_type_t*data_type,
list<pform_port_t>*ports)
{
assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT);
assert(ports);
vector<pform_tf_port_t>*res = new vector<pform_tf_port_t>(0);
PWSRType rt = data_type ? SR_BOTH : SR_PORT;
for (list<pform_port_t>::iterator cur = ports->begin()
; cur != ports->end() ; ++cur) {
perm_string &name = cur->name;
PWire*curw = pform_get_wire_in_scope(name);
if (curw) {
curw->set_port_type(pt);
} else {
curw = new PWire(name, NetNet::IMPLICIT_REG, pt, var_type);
FILE_NAME(curw, loc);
PWire*curw = pform_get_or_make_wire(loc, name, NetNet::IMPLICIT_REG,
pt, vtype, rt);
if (data_type)
curw->set_data_type(data_type);
pform_put_wire_in_scope(name, curw);
}
if (cur->udims) {
if (pform_requires_sv(loc, "Task/function port with unpacked dimensions"))
@ -3256,34 +3227,6 @@ extern void pform_module_specify_path(PSpecPath*obj)
}
static PWire *pform_set_port_type(const struct vlltype&li,
perm_string name, NetNet::PortType pt)
{
PWire*cur = pform_get_wire_in_scope(name);
if (cur == 0) {
cur = new PWire(name, NetNet::IMPLICIT, NetNet::PIMPLICIT, IVL_VT_NO_TYPE);
FILE_NAME(cur, li);
pform_put_wire_in_scope(name, cur);
}
switch (cur->get_port_type()) {
case NetNet::NOT_A_PORT:
case NetNet::PIMPLICIT:
if (! cur->set_port_type(pt))
VLerror("error setting port direction.");
break;
default:
cerr << li << ": error: "
<< "port " << name << " already has a port declaration."
<< endl;
error_count += 1;
break;
}
return cur;
}
void pform_set_port_type(const struct vlltype&li,
list<pform_port_t>*ports,
NetNet::PortType pt,
@ -3306,7 +3249,8 @@ void pform_set_port_type(const struct vlltype&li,
for (list<pform_port_t>::iterator cur = ports->begin()
; cur != ports->end() ; ++ cur ) {
PWire *wire = pform_set_port_type(li, cur->name, pt);
PWire *wire = pform_get_or_make_wire(li, cur->name, NetNet::IMPLICIT, pt,
IVL_VT_NO_TYPE, SR_PORT);
pform_set_net_range(wire, range, signed_flag, SR_PORT, attr);
if (cur->udims) {
cerr << li << ": warning: "