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]);
|
||||
if ((*decl)[idx]->get_port_type() != NetNet::PIMPLICIT) {
|
||||
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) {
|
||||
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 {
|
||||
|
|
@ -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
|
||||
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. */
|
||||
verinum::V init = verinum::Vx;
|
||||
if (init_expr) {
|
||||
// XXXX
|
||||
ivl_assert(loc, pins[0]->get_wire_type() == NetNet::REG);
|
||||
if (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);
|
||||
ivl_assert(*init_expr, pa);
|
||||
auto*pa = dynamic_cast<PAssign*>(init_expr);
|
||||
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());
|
||||
ivl_assert(*init_expr, id);
|
||||
if (pa) {
|
||||
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
|
||||
//ivl_assert(*init_expr, id->name() == pins[0]->name());
|
||||
// XXXX
|
||||
//ivl_assert(*init_expr, id->name() == pins[0]->name());
|
||||
|
||||
const PENumber*np = dynamic_cast<const PENumber*>(pa->rval());
|
||||
ivl_assert(*init_expr, np);
|
||||
auto*np = dynamic_cast<const PENumber*>(pa->rval());
|
||||
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
|
||||
|
|
@ -2159,20 +2215,31 @@ void pform_make_udp(const struct vlltype&loc, perm_string name,
|
|||
registered. Then save the initial value that I get. */
|
||||
verinum::V init = verinum::Vx;
|
||||
if (init_expr) {
|
||||
// XXXX
|
||||
ivl_assert(*init_expr, pins[0]->get_wire_type() == NetNet::REG);
|
||||
bool local_errors = false;
|
||||
|
||||
const PAssign*pa = dynamic_cast<PAssign*>(init_expr);
|
||||
ivl_assert(*init_expr, pa);
|
||||
if (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 = true;
|
||||
}
|
||||
|
||||
const PEIdent*id = dynamic_cast<const PEIdent*>(pa->lval());
|
||||
ivl_assert(*init_expr, id);
|
||||
auto*np = dynamic_cast<const PENumber*>(init_expr);
|
||||
if (!np) {
|
||||
cerr << init_expr->get_fileline() << ": error: "
|
||||
<< "Invalid initial value for primitive "
|
||||
<< name << "." << endl;
|
||||
error_count += 1;
|
||||
local_errors = true;
|
||||
}
|
||||
|
||||
// XXXX
|
||||
//ivl_assert(*init_expr, id->name() == pins[0]->name());
|
||||
|
||||
const PENumber*np = dynamic_cast<const PENumber*>(pa->rval());
|
||||
ivl_assert(*init_expr, np);
|
||||
if (local_errors) {
|
||||
delete parms;
|
||||
delete table;
|
||||
delete init_expr;
|
||||
return;
|
||||
}
|
||||
|
||||
init = np->value()[0];
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue