Report UDP declaration errors instead of asserting
Malformed UDP declarations can reach `pform_make_udp()` with conflicting duplicate port declarations or with an initial value on an output that was not declared as a register. These cases currently trigger internal assertions instead of reporting normal compile errors. The ANSI-style UDP output initializer path also treats the initializer expression as if it was the old-style `initial out = value` assignment statement. This makes a valid `output reg out = 1'b0` initializer assert as well. Report errors for the invalid declarations and read the ANSI-style initializer value directly from the initializer expression. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
parent
025cbcc81f
commit
8d4faf2744
115
pform.cc
115
pform.cc
|
|
@ -1947,11 +1947,25 @@ void pform_make_udp(const struct vlltype&loc, perm_string name,
|
||||||
ivl_assert(loc, (*decl)[idx]);
|
ivl_assert(loc, (*decl)[idx]);
|
||||||
if ((*decl)[idx]->get_port_type() != NetNet::PIMPLICIT) {
|
if ((*decl)[idx]->get_port_type() != NetNet::PIMPLICIT) {
|
||||||
bool rc = cur->set_port_type((*decl)[idx]->get_port_type());
|
bool rc = cur->set_port_type((*decl)[idx]->get_port_type());
|
||||||
ivl_assert(loc, rc);
|
if (!rc) {
|
||||||
|
cerr << loc << ": error: "
|
||||||
|
<< "Port " << port_name << " of primitive "
|
||||||
|
<< name << " has conflicting port declarations."
|
||||||
|
<< endl;
|
||||||
|
error_count += 1;
|
||||||
|
local_errors += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ((*decl)[idx]->get_wire_type() != NetNet::IMPLICIT) {
|
if ((*decl)[idx]->get_wire_type() != NetNet::IMPLICIT) {
|
||||||
bool rc = cur->set_wire_type((*decl)[idx]->get_wire_type());
|
bool rc = cur->set_wire_type((*decl)[idx]->get_wire_type());
|
||||||
ivl_assert(loc, rc);
|
if (!rc) {
|
||||||
|
cerr << loc << ": error: "
|
||||||
|
<< "Port " << port_name << " of primitive "
|
||||||
|
<< name << " has conflicting data declarations."
|
||||||
|
<< endl;
|
||||||
|
error_count += 1;
|
||||||
|
local_errors += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1959,6 +1973,14 @@ void pform_make_udp(const struct vlltype&loc, perm_string name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (local_errors > 0) {
|
||||||
|
delete parms;
|
||||||
|
delete decl;
|
||||||
|
delete table;
|
||||||
|
delete init_expr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Put the parameters into a vector of wire descriptions. Look
|
/* Put the parameters into a vector of wire descriptions. Look
|
||||||
in the map for the definitions of the name. In this loop,
|
in the map for the definitions of the name. In this loop,
|
||||||
|
|
@ -2070,22 +2092,56 @@ void pform_make_udp(const struct vlltype&loc, perm_string name,
|
||||||
registered. Then save the initial value that I get. */
|
registered. Then save the initial value that I get. */
|
||||||
verinum::V init = verinum::Vx;
|
verinum::V init = verinum::Vx;
|
||||||
if (init_expr) {
|
if (init_expr) {
|
||||||
// XXXX
|
if (pins[0]->get_wire_type() != NetNet::REG) {
|
||||||
ivl_assert(loc, pins[0]->get_wire_type() == NetNet::REG);
|
cerr << init_expr->get_fileline() << ": error: "
|
||||||
|
<< "Initial value for primitive " << name
|
||||||
|
<< " requires a registered output port." << endl;
|
||||||
|
error_count += 1;
|
||||||
|
local_errors += 1;
|
||||||
|
}
|
||||||
|
|
||||||
const PAssign*pa = dynamic_cast<PAssign*>(init_expr);
|
auto*pa = dynamic_cast<PAssign*>(init_expr);
|
||||||
ivl_assert(*init_expr, pa);
|
if (!pa) {
|
||||||
|
cerr << init_expr->get_fileline() << ": error: "
|
||||||
|
<< "Invalid initial statement for primitive "
|
||||||
|
<< name << "." << endl;
|
||||||
|
error_count += 1;
|
||||||
|
local_errors += 1;
|
||||||
|
}
|
||||||
|
|
||||||
const PEIdent*id = dynamic_cast<const PEIdent*>(pa->lval());
|
if (pa) {
|
||||||
ivl_assert(*init_expr, id);
|
auto*id = dynamic_cast<const PEIdent*>(pa->lval());
|
||||||
|
if (!id) {
|
||||||
|
cerr << init_expr->get_fileline() << ": error: "
|
||||||
|
<< "Invalid initial statement for primitive "
|
||||||
|
<< name << "." << endl;
|
||||||
|
error_count += 1;
|
||||||
|
local_errors += 1;
|
||||||
|
}
|
||||||
|
|
||||||
// XXXX
|
// XXXX
|
||||||
//ivl_assert(*init_expr, id->name() == pins[0]->name());
|
//ivl_assert(*init_expr, id->name() == pins[0]->name());
|
||||||
|
|
||||||
const PENumber*np = dynamic_cast<const PENumber*>(pa->rval());
|
auto*np = dynamic_cast<const PENumber*>(pa->rval());
|
||||||
ivl_assert(*init_expr, np);
|
if (!np) {
|
||||||
|
cerr << init_expr->get_fileline() << ": error: "
|
||||||
|
<< "Invalid initial value for primitive "
|
||||||
|
<< name << "." << endl;
|
||||||
|
error_count += 1;
|
||||||
|
local_errors += 1;
|
||||||
|
} else {
|
||||||
|
init = np->value()[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (local_errors > 0) {
|
||||||
|
delete parms;
|
||||||
|
delete decl;
|
||||||
|
delete table;
|
||||||
|
delete init_expr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
init = np->value()[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put the primitive into the primitives table
|
// Put the primitive into the primitives table
|
||||||
|
|
@ -2159,20 +2215,31 @@ void pform_make_udp(const struct vlltype&loc, perm_string name,
|
||||||
registered. Then save the initial value that I get. */
|
registered. Then save the initial value that I get. */
|
||||||
verinum::V init = verinum::Vx;
|
verinum::V init = verinum::Vx;
|
||||||
if (init_expr) {
|
if (init_expr) {
|
||||||
// XXXX
|
bool local_errors = false;
|
||||||
ivl_assert(*init_expr, pins[0]->get_wire_type() == NetNet::REG);
|
|
||||||
|
|
||||||
const PAssign*pa = dynamic_cast<PAssign*>(init_expr);
|
if (pins[0]->get_wire_type() != NetNet::REG) {
|
||||||
ivl_assert(*init_expr, pa);
|
cerr << init_expr->get_fileline() << ": error: "
|
||||||
|
<< "Initial value for primitive " << name
|
||||||
|
<< " requires a registered output port." << endl;
|
||||||
|
error_count += 1;
|
||||||
|
local_errors = true;
|
||||||
|
}
|
||||||
|
|
||||||
const PEIdent*id = dynamic_cast<const PEIdent*>(pa->lval());
|
auto*np = dynamic_cast<const PENumber*>(init_expr);
|
||||||
ivl_assert(*init_expr, id);
|
if (!np) {
|
||||||
|
cerr << init_expr->get_fileline() << ": error: "
|
||||||
|
<< "Invalid initial value for primitive "
|
||||||
|
<< name << "." << endl;
|
||||||
|
error_count += 1;
|
||||||
|
local_errors = true;
|
||||||
|
}
|
||||||
|
|
||||||
// XXXX
|
if (local_errors) {
|
||||||
//ivl_assert(*init_expr, id->name() == pins[0]->name());
|
delete parms;
|
||||||
|
delete table;
|
||||||
const PENumber*np = dynamic_cast<const PENumber*>(pa->rval());
|
delete init_expr;
|
||||||
ivl_assert(*init_expr, np);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
init = np->value()[0];
|
init = np->value()[0];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue