Report errors for nets with invalid data type

While a variable can have any data type the data type for nets is quite
restricted.

The SystemVerilog LRM section 6.7.1 ("Net declarations with built-in net
types") requires that the data type of a wire is either a 4-state packed or
a unpacked struct or unpacked array of 4-state packed types.

As an extension to this iverilog allows real data type for wires as well as
2-state packed types.

Add a check that reports an error if a net with any other type is declared.

In addition in Verilog a net can not have an explicit data type at all. It
can only have a packed dimension and a signed flag. As an extension to this
Icarus also allows wires to be of `real` data type.

Note that in Verilog mode the data type is checked in the parser since only
the parser knows whether the data type is an implicit type (`input reg
[7:0]` and `input [7:0] x` elaborate the same). But for SystemVerilog the
type is checked during elaboration since due to forward typedefs and type
parameters the type is not necessarily known in the parser.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2022-01-20 15:59:28 +01:00
parent 027c4828ea
commit 472598dd74
5 changed files with 128 additions and 47 deletions

View File

@ -90,6 +90,90 @@ void Statement::elaborate_sig(Design*, NetScope*) const
{
}
static void sig_check_data_type(Design*des, NetScope*scope,
PWire *wire, NetNet *sig)
{
ivl_type_t type = sig->net_type();
if (!type)
return;
if (type->packed()) {
switch (type->base_type()) {
case IVL_VT_LOGIC: // 4-state packed is allowed by the standard
case IVL_VT_BOOL: // Icarus allows 2-state packed as an extension
return;
default:
break;
}
}
// Icarus allows real nets as an extension
if (type->base_type() == IVL_VT_REAL)
return;
if (wire->symbol_type() == PNamedItem::NET) {
cerr << wire->get_fileline() << ": error: Net `"
<< wire->basename() << "` can not be of type `"
<< sig->data_type() << "`." << endl;
des->errors++;
} else if (scope->type() == NetScope::MODULE &&
sig->port_type() != NetNet::NOT_A_PORT) {
// Module ports only support wire types a the moment
cerr << wire->get_fileline() << ": sorry: Port `"
<< wire->basename() << "` of module `"
<< scope->module_name()
<< "` with type `" << sig->data_type()
<< "` is not supported."
<< endl;
des->errors++;
}
}
static void sig_check_port_type(Design*des, NetScope*scope,
PWire *wire, NetNet *sig)
{
if (sig->port_type() == NetNet::PREF) {
cerr << wire->get_fileline() << ": sorry: "
<< "Reference ports not supported yet." << endl;
des->errors += 1;
}
// Some extra checks for module ports
if (scope->type() != NetScope::MODULE)
return;
/* If the signal is an input and is also declared as a
reg, then report an error. */
if (sig->port_type() == NetNet::PINPUT &&
sig->type() == NetNet::REG) {
cerr << wire->get_fileline() << ": error: Port `"
<< wire->basename() << "` of module `"
<< scope->module_name()
<< "` is declared as input and as a reg type." << endl;
des->errors += 1;
}
if (sig->port_type() == NetNet::PINOUT &&
sig->type() == NetNet::REG) {
cerr << wire->get_fileline() << ": error: Port `"
<< wire->basename() << "` of module `"
<< scope->module_name()
<< "` is declared as inout and as a reg type." << endl;
des->errors += 1;
}
if (sig->port_type() == NetNet::PINOUT &&
sig->data_type() == IVL_VT_REAL) {
cerr << wire->get_fileline() << ": error: Port `"
<< wire->basename() << "` of module `"
<< scope->module_name()
<< "` is declared as a real inout port." << endl;
des->errors += 1;
}
}
bool PScope::elaborate_sig_wires_(Design*des, NetScope*scope) const
{
bool flag = true;
@ -100,53 +184,11 @@ bool PScope::elaborate_sig_wires_(Design*des, NetScope*scope) const
PWire*cur = (*wt).second;
NetNet*sig = cur->elaborate_sig(des, scope);
if (sig && (sig->scope() == scope)
&& (sig->port_type() == NetNet::PREF)) {
if (!sig || sig->scope() != scope)
continue;
cerr << cur->get_fileline() << ": sorry: "
<< "Reference ports not supported yet." << endl;
des->errors += 1;
}
/* If the signal is an input and is also declared as a
reg, then report an error. */
if (sig && (sig->scope() == scope)
&& (scope->type() == NetScope::MODULE)
&& (sig->port_type() == NetNet::PINPUT)
&& (sig->type() == NetNet::REG)) {
cerr << cur->get_fileline() << ": error: Port "
<< cur->basename() << " of module "
<< scope->module_name()
<< " is declared as input and as a reg type." << endl;
des->errors += 1;
}
if (sig && (sig->scope() == scope)
&& (scope->type() == NetScope::MODULE)
&& (sig->port_type() == NetNet::PINOUT)
&& (sig->type() == NetNet::REG)) {
cerr << cur->get_fileline() << ": error: Port "
<< cur->basename() << " of module "
<< scope->module_name()
<< " is declared as inout and as a reg type." << endl;
des->errors += 1;
}
if (sig && (sig->scope() == scope)
&& (scope->type() == NetScope::MODULE)
&& (sig->port_type() == NetNet::PINOUT)
&& (sig->data_type() == IVL_VT_REAL)) {
cerr << cur->get_fileline() << ": error: Port "
<< cur->basename() << " of module "
<< scope->module_name()
<< " is declared as a real inout port." << endl;
des->errors += 1;
}
sig_check_data_type(des, scope, cur, sig);
sig_check_port_type(des, scope, cur, sig);
}

View File

@ -1,4 +1,4 @@
./ivltests/pr2976242c.v:43: error: Port out of module io_real_to_vec is declared as a real inout port.
./ivltests/pr2976242c.v:43: error: Port `out` of module `io_real_to_vec` is declared as a real inout port.
./ivltests/pr2976242c.v:11: error: Cannot connect an arrayed instance of module vec_to_real to real signal r_vec.
./ivltests/pr2976242c.v:14: error: When automatically converting a real port of an arrayed instance to a bit signal
./ivltests/pr2976242c.v:14: : the signal width (5) must be an integer multiple of the instance count (2).

View File

@ -4891,6 +4891,7 @@ module_item
| attribute_list_opt net_type data_type_or_implicit delay3_opt net_variable_list ';'
{ data_type_t*data_type = $3;
pform_check_net_data_type(@2, $2, $3);
if (data_type == 0) {
data_type = new vector_type_t(IVL_VT_LOGIC, false, 0);
FILE_NAME(data_type, @2);
@ -4925,6 +4926,7 @@ module_item
| attribute_list_opt net_type data_type_or_implicit delay3_opt net_decl_assigns ';'
{ data_type_t*data_type = $3;
pform_check_net_data_type(@2, $2, $3);
if (data_type == 0) {
data_type = new vector_type_t(IVL_VT_LOGIC, false, 0);
FILE_NAME(data_type, @2);
@ -4938,6 +4940,7 @@ module_item
| attribute_list_opt net_type data_type_or_implicit drive_strength net_decl_assigns ';'
{ data_type_t*data_type = $3;
pform_check_net_data_type(@2, $2, $3);
if (data_type == 0) {
data_type = new vector_type_t(IVL_VT_LOGIC, false, 0);
FILE_NAME(data_type, @2);

View File

@ -2634,6 +2634,8 @@ void pform_module_define_port(const struct vlltype&li,
return;
}
pform_check_net_data_type(li, type, vtype);
// Packed ranges
list<pform_range_t>*prange = 0;
// Unpacked dimensions
@ -3748,6 +3750,37 @@ bool pform_requires_sv(const struct vlltype&loc, const char *feature)
return false;
}
void pform_check_net_data_type(const struct vlltype&loc, NetNet::Type net_type,
const data_type_t *data_type)
{
// For SystemVerilog the type is checked during elaboration since due to
// forward typedefs and type parameters the actual type might not be known
// yet.
if (gn_system_verilog())
return;
switch (net_type) {
case NetNet::REG:
case NetNet::IMPLICIT_REG:
return;
default:
break;
}
if (!data_type)
return;
const vector_type_t*vec_type = dynamic_cast<const vector_type_t*>(data_type);
if (vec_type && vec_type->implicit_flag)
return;
const real_type_t*rtype = dynamic_cast<const real_type_t*>(data_type);
if (rtype && rtype->type_code() == real_type_t::REAL)
return;
pform_requires_sv(loc, "Net data type");
}
FILE*vl_input = 0;
extern void reset_lexor();

View File

@ -587,4 +587,7 @@ bool pform_requires_sv(const struct vlltype&loc, const char *feature);
void pform_start_parameter_port_list();
void pform_end_parameter_port_list();
void pform_check_net_data_type(const struct vlltype&loc, NetNet::Type net_type,
const data_type_t *data_type);
#endif /* IVL_pform_H */