Merge pull request #820 from larsclausen/array-compatibility

Add error checking for continuous unpacked array assignments
This commit is contained in:
Stephen Williams 2022-12-21 11:38:15 -08:00 committed by GitHub
commit 580d79eae3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 402 additions and 25 deletions

View File

@ -1107,8 +1107,20 @@ NetNet*PEIdent::elaborate_unpacked_net(Design*des, NetScope*scope) const
perm_string method_name;
symbol_search(this, des, scope, path_, sig, par, eve);
if (!sig) {
cerr << get_fileline() << ": error: Net " << path_
<< " is not defined in this context." << endl;
des->errors += 1;
return nullptr;
}
ivl_assert(*this, sig);
const name_component_t&name_tail = path_.back();
if (name_tail.index.size() != 0) {
cerr << get_fileline() << ": sorry: Array slices are not yet "
<< "supported for continuous assignment." << endl;
des->errors += 1;
return nullptr;
}
return sig;
}

View File

@ -260,16 +260,64 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
}
NetNet *elaborate_unpacked_array(Design *des, NetScope *scope, const LineInfo &loc,
const NetNet *lval, PExpr *expr)
{
PEIdent* ident = dynamic_cast<PEIdent*> (expr);
if (!ident) {
des->errors++;
if (dynamic_cast<PEConcat*> (expr)) {
cout << loc.get_fileline() << ": sorry: Continuous assignment"
<< " of array concatenation is not yet supported."
<< endl;
} else if (dynamic_cast<PEAssignPattern*> (expr)) {
cout << loc.get_fileline() << ": sorry: Continuous assignment"
<< " of assignment pattern is not yet supported." << endl;
} else {
cout << loc.get_fileline() << ": error: Can not assign"
<< " non-array expression `" << *expr << "` to array."
<< endl;
}
return nullptr;
}
NetNet *expr_net = ident->elaborate_unpacked_net(des, scope);
if (!expr_net)
return nullptr;
auto const &lval_dims = lval->unpacked_dims();
auto const &expr_dims = expr_net->unpacked_dims();
if (expr_dims.empty()) {
cerr << loc.get_fileline() << ": error: Can not assign"
<< " non-array identifier `" << *expr << "` to array."
<< endl;
des->errors++;
return nullptr;
}
if (!netrange_equivalent(lval_dims, expr_dims)) {
cerr << loc.get_fileline() << ": error: Unpacked dimensions"
<< " are not compatible in array assignment." << endl;
des->errors++;
return nullptr;
}
if (!lval->net_type()->type_equivalent(expr_net->net_type())) {
cerr << loc.get_fileline() << ": error: Element types are not"
<< " compatible in array assignment." << endl;
des->errors++;
return nullptr;
}
return expr_net;
}
void PGAssign::elaborate_unpacked_array_(Design*des, NetScope*scope, NetNet*lval) const
{
PEIdent*rval_pident = dynamic_cast<PEIdent*> (pin(1));
ivl_assert(*this, rval_pident);
NetNet*rval_net = rval_pident->elaborate_unpacked_net(des, scope);
ivl_assert(*this, rval_net->pin_count() == lval->pin_count());
assign_unpacked_with_bufz(des, scope, this, lval, rval_net);
NetNet *rval_net = elaborate_unpacked_array(des, scope, *this, lval, pin(1));
if (rval_net)
assign_unpacked_with_bufz(des, scope, lval, lval, rval_net);
}
void PGBuiltin::calculate_gate_and_lval_count_(unsigned&gate_count,
@ -1147,6 +1195,29 @@ static void isolate_and_connect(Design*des, NetScope*scope, const PGModule*mod,
}
}
void elaborate_unpacked_port(Design *des, NetScope *scope, NetNet *port_net,
PExpr *expr, NetNet::PortType port_type,
Module *mod, unsigned int port_idx)
{
NetNet *expr_net = elaborate_unpacked_array(des, scope, *expr, port_net,
expr);
if (!expr_net) {
perm_string port_name = mod->get_port_name(port_idx);
cerr << expr->get_fileline() << ": : Port "
<< port_idx+1 << " (" << port_name << ") of "
<< mod->mod_name() << " is connected to "
<< *expr << endl;
return;
}
ivl_assert(*port_net, expr_net->pin_count() == port_net->pin_count());
if (port_type == NetNet::POUTPUT)
assign_unpacked_with_bufz(des, scope, port_net, expr_net, port_net);
else
assign_unpacked_with_bufz(des, scope, port_net, port_net, expr_net);
}
/*
* Instantiate a module by recursively elaborating it. Set the path of
* the recursive elaboration so that signal names get properly
@ -1481,13 +1552,8 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
// differently.
if (prts.size() >= 1 && prts[0]->pin_count()>1) {
ivl_assert(*this, prts.size()==1);
PEIdent*rval_pident = dynamic_cast<PEIdent*> (pins[idx]);
ivl_assert(*this, rval_pident);
NetNet*rval_net = rval_pident->elaborate_unpacked_net(des, scope);
ivl_assert(*this, rval_net->pin_count() == prts[0]->pin_count());
assign_unpacked_with_bufz(des, scope, this, prts[0], rval_net);
elaborate_unpacked_port(des, scope, prts[0], pins[idx],
ptype, rmod, idx);
continue;
}
@ -1650,15 +1716,8 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
// "r-value" expression, but since this is an
// output port, we assign to it from the internal object.
if (prts[0]->pin_count() > 1) {
ivl_assert(*this, prts.size()==1);
PEIdent*rval_pident = dynamic_cast<PEIdent*>(pins[idx]);
ivl_assert(*this, rval_pident);
NetNet*rval_net = rval_pident->elaborate_unpacked_net(des, scope);
ivl_assert(*this, rval_net->pin_count() == prts[0]->pin_count());
assign_unpacked_with_bufz(des, scope, this, rval_net, prts[0]);
elaborate_unpacked_port(des, scope, prts[0], pins[idx],
ptype, rmod, idx);
continue;
}

View File

@ -0,0 +1,14 @@
// Check that continuous assignment of two compatible arrays is supported
module test;
wire [1:0] x[1:0];
wire [1:0] y[1:0];
assign x = y;
initial begin
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,16 @@
// Check that continuous assignment of two compatible arrays is supported, even
// if the upper and lower bounds of the arrays are not identical, as long as the
// size is the same.
module test;
wire [1:0] x[1:0];
wire [1:0] y[2:1];
assign x = y;
initial begin
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,15 @@
// Check that continuous assignment of two compatible arrays is supported, even
// if the element types are not identical, but just equivalent.
module test;
wire [1:0] x[1:0];
wire [2:1] y[1:0];
assign x = y;
initial begin
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,16 @@
// Check that continuous assignment of two compatible arrays is supported, even
// if the element types are not identical and one is a built-in integer and the
// other a equivalent packed type.
module test;
wire signed [31:0] x[1:0];
wire integer y[1:0];
assign x = y;
initial begin
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,16 @@
// Check that continuous assignment of two compatible arrays is supported, even
// if the element types have different number of dimensions, but have the same
// packed width.
module test;
wire [3:0] x[1:0];
wire [1:0][1:0] y[1:0];
assign x = y;
initial begin
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,15 @@
// Check that it is an error if the element type is not the same in a
// continuous array assignment.
module test;
wire [3:0] x[1:0];
reg [1:0] y[1:0];
assign x = y;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,18 @@
// Check that it is an error trying to continuously assign an unpacked array
// with an enum element type to another unpacked array with an element type that
// is not the same enum type, even if the two element types are the same size.
module test;
wire integer x[1:0];
enum integer {
A
} y[1:0];
assign x = y;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,18 @@
// Check that it is an error to continuously assign an unpacked array with an
// enum element type if the other unpacked array element type is not the same
// enum type, even if the two element types are the same size.
module test;
wire enum integer {
A
} x[1:0];
integer y[1:0];
assign x = y;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,15 @@
// Check that it is an error if the array size is not the same in a continuous
// unpacked array assignment.
module test;
wire [1:0] x[2:0];
reg [1:0] y[1:0];
assign x = y;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,16 @@
// Check that it is an error if the number of unpacked dimensions do not match
// in an continuous array assignment, even if the canonical size of the array is
// the same.
module test;
wire [1:0] x[1:0][1:0];
reg [1:0] y[3:0];
assign x = y;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,16 @@
// Check that it is an error if the element type is not the same in a
// continuous array assignment, even if the difference is just 2-state vs.
// 4-state.
module test;
wire [1:0] x[1:0];
bit [1:0] y[1:0];
assign x = y;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,16 @@
// Check that it is an error if the element type is not the same in a
// continuous array assignment, even if one of the types is a packed type and
// the other is a real type.
module test;
wire [1:0] x[1:0];
real [1:0] y[1:0];
assign x = y;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,14 @@
// Check that it is an error trying to continuously assign a scalar expression
// to a unpacked array.
module test;
wire [1:0] x[1:0];
assign x = 1'b1 + 1'b1;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,15 @@
// Check that it is an error trying to continuously assign a scalar variable to
// an unpacked array.
module test;
wire [1:0] x[1:0];
reg [1:0] y;
assign x = y;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,15 @@
// Check that it is an error trying to continuously assign a scalar net to an
// unpacked array.
module test;
wire a[1:0];
wire x;
assign a = x;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,15 @@
// Check that it is an error trying to continuously assign an element of an
// unpacked array to another unpacked array as a whole.
module test;
wire a[1:0];
wire x[1:0];
assign a = x[0];
initial begin
$display("FAILED");
end
endmodule

View File

@ -501,6 +501,22 @@ sv_assign_pattern_func normal,-g2005-sv ivltests
sv_assign_pattern_op normal,-g2005-sv ivltests
sv_assign_pattern_part normal,-g2005-sv ivltests
sv_array_assign_pattern2 normal,-g2009 ivltests
sv_array_cassign1 normal,-g2005-sv ivltests
sv_array_cassign2 normal,-g2005-sv ivltests
sv_array_cassign3 normal,-g2005-sv ivltests
sv_array_cassign4 normal,-g2005-sv ivltests
sv_array_cassign5 normal,-g2005-sv ivltests
sv_array_cassign_fail1 CE,-g2005-sv ivltests
sv_array_cassign_fail2 CE,-g2005-sv ivltests
sv_array_cassign_fail3 CE,-g2005-sv ivltests
sv_array_cassign_fail4 CE,-g2005-sv ivltests
sv_array_cassign_fail5 CE,-g2005-sv ivltests
sv_array_cassign_fail6 CE,-g2005-sv ivltests
sv_array_cassign_fail7 CE,-g2005-sv ivltests
sv_array_cassign_fail8 CE,-g2005-sv ivltests
sv_array_cassign_fail9 CE,-g2005-sv ivltests
sv_array_cassign_fail10 CE,-g2005-sv ivltests
sv_array_cassign_fail11 CE,-g2005-sv ivltests
sv_array_query normal,-g2005-sv ivltests
sv_cast_integer normal,-g2005-sv ivltests
sv_cast_integer2 normal,-g2005-sv ivltests

View File

@ -257,6 +257,11 @@ scan-invalid CE ivltests
sel_rval_bit_ob CE ivltests
sel_rval_part_ob CE ivltests
signed_net_display CE,-pallowsigned=1 ivltests
sv_array_cassign1 CE,-g2005-sv ivltests
sv_array_cassign2 CE,-g2005-sv ivltests
sv_array_cassign3 CE,-g2005-sv ivltests
sv_array_cassign4 CE,-g2005-sv ivltests
sv_array_cassign5 CE,-g2005-sv ivltests
sv_unpacked_port CE,-g2009 ivltests
sv_unpacked_port2 CE,-g2009,-pallowsigned=1 ivltests
sv_unpacked_wire CE,-g2009 ivltests

View File

@ -86,3 +86,15 @@ vector<netrange_t> netuarray_t::slice_dimensions() const
{
return static_dimensions();
}
bool netuarray_t::test_equivalence(ivl_type_t that) const
{
const netuarray_t *that_a = dynamic_cast<const netuarray_t *>(that);
if (!that_a)
return false;
if (!netrange_equivalent(static_dimensions(), that_a->static_dimensions()))
return false;
return element_type()->type_equivalent(that_a->element_type());
}

View File

@ -92,6 +92,9 @@ class netuarray_t : public netsarray_t {
public:
// Virtual methods from the ivl_type_s type...
std::vector<netrange_t> slice_dimensions() const;
private:
bool test_equivalence(ivl_type_t that) const;
};
inline netuarray_t::netuarray_t(const std::vector<netrange_t>&pd,

View File

@ -109,6 +109,20 @@ unsigned long netrange_width(const vector<netrange_t>&packed)
return wid;
}
bool netrange_equivalent(const std::vector<netrange_t> &a,
const std::vector<netrange_t> &b)
{
if (a.size() != b.size())
return false;
for (size_t i = 0; i < a.size(); i++) {
if (!a[i].equivalent(b[i]))
return false;
}
return true;
}
/*
* Given a netrange_t list (which represent packed dimensions) and a
* prefix of calculated index values, calculate the canonical offset

View File

@ -137,6 +137,10 @@ class netrange_t {
return false;
}
bool equivalent(const netrange_t &that) const {
return width() == that.width();
}
private:
long msb_;
long lsb_;
@ -146,6 +150,8 @@ extern std::ostream&operator << (std::ostream&out, const std::list<netrange_t>&r
extern std::ostream&operator << (std::ostream&out, const std::vector<netrange_t>&rlist);
extern unsigned long netrange_width(const std::vector<netrange_t>&dims);
extern bool netrange_equivalent(const std::vector<netrange_t> &a,
const std::vector<netrange_t> &b);
/*
* There are a few cases where we need to know about the single-level