Merge pull request #820 from larsclausen/array-compatibility
Add error checking for continuous unpacked array assignments
This commit is contained in:
commit
580d79eae3
14
elab_net.cc
14
elab_net.cc
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
107
elaborate.cc
107
elaborate.cc
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
12
netparray.cc
12
netparray.cc
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
14
nettypes.cc
14
nettypes.cc
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue