Merge pull request #953 from larsclausen/assign-pattern-uarray
Add initial support for array assignment patterns
This commit is contained in:
commit
df8ac73bba
9
PExpr.h
9
PExpr.h
|
|
@ -222,8 +222,13 @@ class PEAssignPattern : public PExpr {
|
|||
NetExpr* elaborate_expr_struct_(Design *des, NetScope *scope,
|
||||
const netstruct_t *struct_type,
|
||||
bool need_const) const;
|
||||
NetExpr* elaborate_expr_darray_(Design *des, NetScope *scope,
|
||||
const netdarray_t *array_type,
|
||||
NetExpr* elaborate_expr_array_(Design *des, NetScope *scope,
|
||||
const netarray_t *array_type,
|
||||
bool need_const, bool up) const;
|
||||
NetExpr* elaborate_expr_uarray_(Design *des, NetScope *scope,
|
||||
const netuarray_t *uarray_type,
|
||||
const std::vector<netrange_t> &dims,
|
||||
unsigned int cur_dim,
|
||||
bool need_const) const;
|
||||
|
||||
private:
|
||||
|
|
|
|||
97
elab_expr.cc
97
elab_expr.cc
|
|
@ -142,6 +142,11 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_type_t lv_net_type,
|
|||
break;
|
||||
}
|
||||
|
||||
// If the target is an unpacked array we want full type checking,
|
||||
// regardless of the base type of the array.
|
||||
if (dynamic_cast<const netuarray_t *>(lv_net_type))
|
||||
typed_elab = true;
|
||||
|
||||
// Special case, PEAssignPattern is context dependend on the type and
|
||||
// always uses the typed elaboration
|
||||
if (dynamic_cast<PEAssignPattern*>(expr))
|
||||
|
|
@ -236,7 +241,13 @@ NetExpr*PEAssignPattern::elaborate_expr(Design*des, NetScope*scope,
|
|||
bool need_const = NEED_CONST & flags;
|
||||
|
||||
if (auto darray_type = dynamic_cast<const netdarray_t*>(ntype))
|
||||
return elaborate_expr_darray_(des, scope, darray_type, need_const);
|
||||
return elaborate_expr_array_(des, scope, darray_type, need_const, true);
|
||||
|
||||
if (auto uarray_type = dynamic_cast<const netuarray_t*>(ntype)) {
|
||||
return elaborate_expr_uarray_(des, scope, uarray_type,
|
||||
uarray_type->static_dimensions(), 0,
|
||||
need_const);
|
||||
}
|
||||
|
||||
if (auto parray_type = dynamic_cast<const netparray_t*>(ntype)) {
|
||||
return elaborate_expr_packed_(des, scope, parray_type->base_type(),
|
||||
|
|
@ -265,9 +276,9 @@ NetExpr*PEAssignPattern::elaborate_expr(Design*des, NetScope*scope,
|
|||
return 0;
|
||||
}
|
||||
|
||||
NetExpr* PEAssignPattern::elaborate_expr_darray_(Design *des, NetScope *scope,
|
||||
const netdarray_t *array_type,
|
||||
bool need_const) const
|
||||
NetExpr* PEAssignPattern::elaborate_expr_array_(Design *des, NetScope *scope,
|
||||
const netarray_t *array_type,
|
||||
bool need_const, bool up) const
|
||||
{
|
||||
// Special case: If this is an empty pattern (i.e. '{}) then convert
|
||||
// this to a null handle. Internally, Icarus Verilog uses this to
|
||||
|
|
@ -283,10 +294,14 @@ NetExpr* PEAssignPattern::elaborate_expr_darray_(Design *des, NetScope *scope,
|
|||
// element_type expressions.
|
||||
ivl_type_t elem_type = array_type->element_type();
|
||||
vector<NetExpr*> elem_exprs (parms_.size());
|
||||
size_t elem_idx = up ? 0 : parms_.size() - 1;
|
||||
for (size_t idx = 0 ; idx < parms_.size() ; idx += 1) {
|
||||
NetExpr*tmp = elaborate_rval_expr(des, scope, elem_type,
|
||||
parms_[idx], need_const);
|
||||
elem_exprs[idx] = tmp;
|
||||
elem_exprs[elem_idx] = elaborate_rval_expr(des, scope, elem_type,
|
||||
parms_[idx], need_const);
|
||||
if (up)
|
||||
elem_idx++;
|
||||
else
|
||||
elem_idx--;
|
||||
}
|
||||
|
||||
NetEArrayPattern*res = new NetEArrayPattern(array_type, elem_exprs);
|
||||
|
|
@ -294,6 +309,74 @@ NetExpr* PEAssignPattern::elaborate_expr_darray_(Design *des, NetScope *scope,
|
|||
return res;
|
||||
}
|
||||
|
||||
NetExpr* PEAssignPattern::elaborate_expr_uarray_(Design *des, NetScope *scope,
|
||||
const netuarray_t *uarray_type,
|
||||
const std::vector<netrange_t> &dims,
|
||||
unsigned int cur_dim,
|
||||
bool need_const) const
|
||||
{
|
||||
if (dims.size() <= cur_dim)
|
||||
return nullptr;
|
||||
|
||||
if (dims[cur_dim].width() != parms_.size()) {
|
||||
cerr << get_fileline() << ": error: Unpacked array assignment pattern expects "
|
||||
<< dims[cur_dim].width() << " element(s) in this context.\n"
|
||||
<< get_fileline() << ": : Found "
|
||||
<< parms_.size() << " element(s)." << endl;
|
||||
des->errors++;
|
||||
}
|
||||
|
||||
bool up = dims[cur_dim].get_msb() < dims[cur_dim].get_lsb();
|
||||
if (cur_dim == dims.size() - 1) {
|
||||
return elaborate_expr_array_(des, scope, uarray_type, need_const, up);
|
||||
}
|
||||
|
||||
cur_dim++;
|
||||
vector<NetExpr*> elem_exprs(parms_.size());
|
||||
size_t elem_idx = up ? 0 : parms_.size() - 1;
|
||||
for (size_t idx = 0; idx < parms_.size(); idx++) {
|
||||
NetExpr *expr = nullptr;
|
||||
// Handle nested assignment patterns as a special case. We do not
|
||||
// have a good way of passing the inner dimensions through the
|
||||
// generic elaborate_expr() API and assigment patterns is the only
|
||||
// place where we need it.
|
||||
if (auto ap = dynamic_cast<PEAssignPattern*>(parms_[idx])) {
|
||||
expr = ap->elaborate_expr_uarray_(des, scope, uarray_type,
|
||||
dims, cur_dim, need_const);
|
||||
} else if (dynamic_cast<PEConcat*>(parms_[idx])) {
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "Array concatenation is not yet supported."
|
||||
<< endl;
|
||||
des->errors++;
|
||||
} else if (dynamic_cast<PEIdent*>(parms_[idx])) {
|
||||
// The only other thing that's allow in this
|
||||
// context is an array slice or identifier.
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "Procedural assignment of array or array slice"
|
||||
<< " is not yet supported." << endl;
|
||||
des->errors++;
|
||||
} else if (parms_[idx]) {
|
||||
cerr << get_fileline() << ": error: Expression "
|
||||
<< *parms_[idx]
|
||||
<< " is not compatible with this context."
|
||||
<< " Expected array or array-like expression."
|
||||
<< endl;
|
||||
des->errors++;
|
||||
}
|
||||
|
||||
elem_exprs[elem_idx] = expr;
|
||||
|
||||
if (up)
|
||||
elem_idx++;
|
||||
else
|
||||
elem_idx--;
|
||||
}
|
||||
|
||||
NetEArrayPattern *res = new NetEArrayPattern(uarray_type, elem_exprs);
|
||||
res->set_line(*this);
|
||||
return res;
|
||||
}
|
||||
|
||||
NetExpr* PEAssignPattern::elaborate_expr_packed_(Design *des, NetScope *scope,
|
||||
ivl_variable_type_t base_type,
|
||||
unsigned int width,
|
||||
|
|
|
|||
|
|
@ -242,8 +242,12 @@ NetAssign_*PEIdent::elaborate_lval_var_(Design *des, NetScope *scope,
|
|||
// is less than the array dimensions (unpacked).
|
||||
if (reg->unpacked_dimensions() > name_tail.index.size()) {
|
||||
if (gn_system_verilog()) {
|
||||
cerr << get_fileline() << ": sorry: Assignment to an entire"
|
||||
" array or to an array slice is not yet supported."
|
||||
if (name_tail.index.empty()) {
|
||||
NetAssign_*lv = new NetAssign_(reg);
|
||||
return lv;
|
||||
}
|
||||
cerr << get_fileline() << ": sorry: Assignment to an "
|
||||
" array slice is not yet supported."
|
||||
<< endl;
|
||||
} else {
|
||||
cerr << get_fileline() << ": error: Assignment to an entire"
|
||||
|
|
|
|||
19
elaborate.cc
19
elaborate.cc
|
|
@ -251,25 +251,29 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
|
|||
NetNet *elaborate_unpacked_array(Design *des, NetScope *scope, const LineInfo &loc,
|
||||
const NetNet *lval, PExpr *expr)
|
||||
{
|
||||
NetNet *expr_net;
|
||||
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;
|
||||
des->errors++;
|
||||
return nullptr;
|
||||
} else if (dynamic_cast<PEAssignPattern*> (expr)) {
|
||||
cout << loc.get_fileline() << ": sorry: Continuous assignment"
|
||||
<< " of assignment pattern is not yet supported." << endl;
|
||||
auto net_expr = elaborate_rval_expr(des, scope, lval->array_type(), expr);
|
||||
expr_net = net_expr->synthesize(des, scope, net_expr);
|
||||
} else {
|
||||
cout << loc.get_fileline() << ": error: Can not assign"
|
||||
<< " non-array expression `" << *expr << "` to array."
|
||||
<< endl;
|
||||
des->errors++;
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
} else {
|
||||
expr_net = ident->elaborate_unpacked_net(des, scope);
|
||||
}
|
||||
|
||||
NetNet *expr_net = ident->elaborate_unpacked_net(des, scope);
|
||||
if (!expr_net)
|
||||
return nullptr;
|
||||
|
||||
|
|
@ -2642,8 +2646,9 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
|
|||
cerr << get_fileline() << ": PAssign::elaborate: "
|
||||
<< "lv->word() = <nil>" << endl;
|
||||
}
|
||||
ivl_assert(*this, lv->word());
|
||||
ivl_type_t use_lv_type = utype->element_type();
|
||||
ivl_type_t use_lv_type = lv_net_type;
|
||||
if (lv->word())
|
||||
use_lv_type = utype->element_type();
|
||||
|
||||
ivl_assert(*this, use_lv_type);
|
||||
rv = elaborate_rval_(des, scope, use_lv_type);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
# include "netlist.h"
|
||||
# include "netvector.h"
|
||||
# include "netparray.h"
|
||||
# include "netmisc.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
|
|
@ -813,6 +814,58 @@ NetNet* NetEConcat::synthesize(Design*des, NetScope*scope, NetExpr*root)
|
|||
return osig;
|
||||
}
|
||||
|
||||
NetNet *NetEArrayPattern::synthesize(Design *des, NetScope *scope, NetExpr *root)
|
||||
{
|
||||
const netsarray_t *array_type = dynamic_cast<const netsarray_t *>(net_type());
|
||||
ivl_assert(*this, array_type);
|
||||
|
||||
if (items_.empty())
|
||||
return nullptr;
|
||||
|
||||
bool failed = false;
|
||||
|
||||
std::unique_ptr<NetNet*[]> nets(new NetNet*[items_.size()]);
|
||||
for (unsigned int idx = 0; idx < items_.size(); idx++) {
|
||||
if (!items_[idx]) {
|
||||
failed = true;
|
||||
continue;
|
||||
}
|
||||
nets[idx] = items_[idx]->synthesize(des, scope, root);
|
||||
if (!nets[idx])
|
||||
failed = true;
|
||||
}
|
||||
|
||||
if (failed)
|
||||
return nullptr;
|
||||
|
||||
// Infer which dimension we are in for nested assignment patterns based on
|
||||
// the dimensions of the element.
|
||||
size_t dim = nets[0]->unpacked_dims().size() + 1;
|
||||
const auto &type_dims = array_type->static_dimensions();
|
||||
|
||||
if (dim > type_dims.size())
|
||||
return nullptr;
|
||||
|
||||
std::list<netrange_t> dims(type_dims.end() - dim, type_dims.end());
|
||||
|
||||
if (dims.front().width() != items_.size())
|
||||
return nullptr;
|
||||
|
||||
perm_string path = scope->local_symbol();
|
||||
NetNet *osig = new NetNet(scope, path, NetNet::IMPLICIT, dims,
|
||||
array_type->element_type());
|
||||
osig->set_line(*this);
|
||||
osig->local_flag(true);
|
||||
|
||||
unsigned int opin = 0;
|
||||
for (unsigned int idx = 0; idx < items_.size(); idx++) {
|
||||
for (unsigned int net_pin = 0; net_pin < nets[idx]->pin_count(); net_pin++)
|
||||
connect(osig->pin(opin++), nets[idx]->pin(net_pin));
|
||||
}
|
||||
|
||||
return osig;
|
||||
}
|
||||
|
||||
NetNet* NetEConst::synthesize(Design*des, NetScope*scope, NetExpr*)
|
||||
{
|
||||
perm_string path = scope->local_symbol();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
// Check that procedural assignment of unpacked array assignment patterns is
|
||||
// supported and a entries are assigned in the right order.
|
||||
|
||||
module test;
|
||||
|
||||
bit failed;
|
||||
|
||||
`define check(val, exp) do \
|
||||
if (val !== exp) begin \
|
||||
$display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); \
|
||||
failed = 1'b1; \
|
||||
end \
|
||||
while(0)
|
||||
|
||||
int x[3:0];
|
||||
int y[0:3];
|
||||
int z[4];
|
||||
|
||||
initial begin
|
||||
x = '{1'b1, 1 + 1, 3.3, "TEST"};
|
||||
y = '{1'b1, 1 + 1, 3.3, "TEST"};
|
||||
z = '{1'b1, 1 + 1, 3.3, "TEST"};
|
||||
|
||||
`check(x[0], 1413829460);
|
||||
`check(x[1], 3);
|
||||
`check(x[2], 2);
|
||||
`check(x[3], 1);
|
||||
|
||||
`check(y[0], 1);
|
||||
`check(y[1], 2);
|
||||
`check(y[2], 3);
|
||||
`check(y[3], 1413829460);
|
||||
|
||||
`check(z[0], 1);
|
||||
`check(z[1], 2);
|
||||
`check(z[2], 3);
|
||||
`check(z[3], 1413829460);
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// Check that procedural assignment of unpacked array assignment patterns to
|
||||
// multi-dimensional arrays is supported and entries are assigned in the right
|
||||
// order.
|
||||
|
||||
module test;
|
||||
|
||||
bit failed;
|
||||
|
||||
`define check(val, exp) do \
|
||||
if (val !== exp) begin \
|
||||
$display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); \
|
||||
failed = 1'b1; \
|
||||
end \
|
||||
while(0)
|
||||
|
||||
int x[1:0][1:0];
|
||||
int y[1:0][0:1];
|
||||
int z[2][2];
|
||||
|
||||
initial begin
|
||||
x = '{'{1'b1, 1 + 1}, '{3.3, "TEST"}};
|
||||
y = '{'{1'b1, 1 + 1}, '{3.3, "TEST"}};
|
||||
z = '{'{1'b1, 1 + 1}, '{3.3, "TEST"}};
|
||||
|
||||
`check(x[0][0], 1413829460);
|
||||
`check(x[0][1], 3);
|
||||
`check(x[1][0], 2);
|
||||
`check(x[1][1], 1);
|
||||
|
||||
`check(y[0][0], 3);
|
||||
`check(y[0][1], 1413829460);
|
||||
`check(y[1][0], 1);
|
||||
`check(y[1][1], 2);
|
||||
|
||||
`check(z[0][0], 1);
|
||||
`check(z[0][1], 2);
|
||||
`check(z[1][0], 3);
|
||||
`check(z[1][1], 1413829460);
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
// Check that continuous assignment of unpacked array assignment patterns is
|
||||
// supported and entries are assigned in the right order.
|
||||
|
||||
module test;
|
||||
|
||||
bit failed;
|
||||
|
||||
`define check(val, exp) do \
|
||||
if (val !== exp) begin \
|
||||
$display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); \
|
||||
failed = 1'b1; \
|
||||
end \
|
||||
while(0)
|
||||
|
||||
int x[3:0];
|
||||
int y[0:3];
|
||||
int z[4];
|
||||
|
||||
assign x = '{1'b1, 1 + 1, 3.3, "TEST"};
|
||||
assign y = '{1'b1, 1 + 1, 3.3, "TEST"};
|
||||
assign z = '{1'b1, 1 + 1, 3.3, "TEST"};
|
||||
|
||||
initial begin
|
||||
`check(x[0], 1413829460);
|
||||
`check(x[1], 3);
|
||||
`check(x[2], 2);
|
||||
`check(x[3], 1);
|
||||
|
||||
`check(y[0], 1);
|
||||
`check(y[1], 2);
|
||||
`check(y[2], 3);
|
||||
`check(y[3], 1413829460);
|
||||
|
||||
`check(z[0], 1);
|
||||
`check(z[1], 2);
|
||||
`check(z[2], 3);
|
||||
`check(z[3], 1413829460);
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// Check that continuous assignment of unpacked array assignment patterns to
|
||||
// multi-dimensional arrays is supported and entries are assigned in the right
|
||||
// order.
|
||||
|
||||
module test;
|
||||
|
||||
bit failed;
|
||||
|
||||
`define check(val, exp) do \
|
||||
if (val !== exp) begin \
|
||||
$display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); \
|
||||
failed = 1'b1; \
|
||||
end \
|
||||
while(0)
|
||||
|
||||
int x[1:0][1:0];
|
||||
int y[1:0][0:1];
|
||||
int z[2][2];
|
||||
|
||||
assign x = '{'{1'b1, 1 + 1}, '{3.3, "TEST"}};
|
||||
assign y = '{'{1'b1, 1 + 1}, '{3.3, "TEST"}};
|
||||
assign z = '{'{1'b1, 1 + 1}, '{3.3, "TEST"}};
|
||||
|
||||
initial begin
|
||||
`check(x[0][0], 1413829460);
|
||||
`check(x[0][1], 3);
|
||||
`check(x[1][0], 2);
|
||||
`check(x[1][1], 1);
|
||||
|
||||
`check(y[0][0], 3);
|
||||
`check(y[0][1], 1413829460);
|
||||
`check(y[1][0], 1);
|
||||
`check(y[1][1], 2);
|
||||
|
||||
`check(z[0][0], 1);
|
||||
`check(z[0][1], 2);
|
||||
`check(z[1][0], 3);
|
||||
`check(z[1][1], 1413829460);
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// Check that procedural assignment of unpacked real array assignment patterns
|
||||
// to multi-dimensional arrays is supported and entries are assigned in the
|
||||
// right order.
|
||||
|
||||
module test;
|
||||
|
||||
bit failed;
|
||||
|
||||
`define check(val, exp) do \
|
||||
if (val != exp) begin \
|
||||
$display("FAILED(%0d). '%s' expected %0f, got %0f", `__LINE__, `"val`", exp, val); \
|
||||
failed = 1'b1; \
|
||||
end \
|
||||
while(0)
|
||||
|
||||
real x[1:0][1:0];
|
||||
real y[1:0][0:1];
|
||||
real z[2][2];
|
||||
|
||||
initial begin
|
||||
x = '{'{1'b1, 1 + 1}, '{3.3, "TEST"}};
|
||||
y = '{'{1'b1, 1 + 1}, '{3.3, "TEST"}};
|
||||
z = '{'{1'b1, 1 + 1}, '{3.3, "TEST"}};
|
||||
|
||||
`check(x[0][0], 1413829460.0);
|
||||
`check(x[0][1], 3.3);
|
||||
`check(x[1][0], 2.0);
|
||||
`check(x[1][1], 1.0);
|
||||
|
||||
`check(y[0][1], 1413829460.0);
|
||||
`check(y[0][0], 3.3);
|
||||
`check(y[1][1], 2.0);
|
||||
`check(y[1][0], 1.0);
|
||||
|
||||
`check(z[0][0], 1.0);
|
||||
`check(z[0][1], 2.0);
|
||||
`check(z[1][0], 3.3);
|
||||
`check(z[1][1], 1413829460.0);
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// Check that procedural assignment of unpacked string array assignment patterns
|
||||
// to multi-dimensional arrays is supported and entries are assigned in the
|
||||
// right order.
|
||||
|
||||
module test;
|
||||
|
||||
bit failed;
|
||||
|
||||
`define check(val, exp) do \
|
||||
if (val != exp) begin \
|
||||
$display("FAILED(%0d). '%s' expected %s, got %s", `__LINE__, `"val`", exp, val); \
|
||||
failed = 1'b1; \
|
||||
end \
|
||||
while(0)
|
||||
|
||||
string x[1:0][1:0];
|
||||
string y[1:0][0:1];
|
||||
string z[2][2];
|
||||
|
||||
initial begin
|
||||
x = '{'{"Hello", "World"}, '{"Array", "Pattern"}};
|
||||
y = '{'{"Hello", "World"}, '{"Array", "Pattern"}};
|
||||
z = '{'{"Hello", "World"}, '{"Array", "Pattern"}};
|
||||
|
||||
`check(x[0][0], "Pattern");
|
||||
`check(x[0][1], "Array");
|
||||
`check(x[1][0], "World");
|
||||
`check(x[1][1], "Hello");
|
||||
|
||||
`check(y[0][0], "Array");
|
||||
`check(y[0][1], "Pattern");
|
||||
`check(y[1][0], "Hello");
|
||||
`check(y[1][1], "World");
|
||||
|
||||
`check(z[0][0], "Hello");
|
||||
`check(z[0][1], "World");
|
||||
`check(z[1][0], "Array");
|
||||
`check(z[1][1], "Pattern");
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// Check that an unpacked array assignment pattern with too many elements
|
||||
// results in an error.
|
||||
|
||||
module test;
|
||||
|
||||
int x[1:0];
|
||||
|
||||
initial begin
|
||||
x = '{1, 2, 3}; // Should fail, more elements in assignment pattern than
|
||||
// array size.
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// Check that an unpacked array assignment pattern with not enough elements
|
||||
// results in an error.
|
||||
|
||||
module test;
|
||||
|
||||
int x[1:0];
|
||||
|
||||
initial begin
|
||||
x = '{1}; // Should fail, less elements in assignment pattern than array
|
||||
// size.
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// Check that trying to do a procedural assign of a scalar to an array results
|
||||
// in an error.
|
||||
|
||||
module test;
|
||||
|
||||
integer x[1:0];
|
||||
|
||||
initial begin
|
||||
x = 10; // Error, scalar assigned to array
|
||||
$display("FAILED");
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// Check that trying to do a continuous assign of a scalar to an array results
|
||||
// in an error.
|
||||
|
||||
module test;
|
||||
|
||||
integer x[1:0];
|
||||
|
||||
assign x = 10; // Error, scalar assigned to array
|
||||
|
||||
initial begin
|
||||
$display("FAILED");
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -45,6 +45,16 @@ pv_wr_fn_vec2 vvp_tests/pv_wr_fn_vec2.json
|
|||
pv_wr_fn_vec4 vvp_tests/pv_wr_fn_vec4.json
|
||||
struct_packed_write_read vvp_tests/struct_packed_write_read.json
|
||||
struct_packed_write_read2 vvp_tests/struct_packed_write_read2.json
|
||||
sv_ap_uarray1 vvp_tests/sv_ap_uarray1.json
|
||||
sv_ap_uarray2 vvp_tests/sv_ap_uarray2.json
|
||||
sv_ap_uarray3 vvp_tests/sv_ap_uarray3.json
|
||||
sv_ap_uarray4 vvp_tests/sv_ap_uarray4.json
|
||||
sv_ap_uarray5 vvp_tests/sv_ap_uarray5.json
|
||||
sv_ap_uarray6 vvp_tests/sv_ap_uarray6.json
|
||||
sv_ap_uarray_fail1 vvp_tests/sv_ap_uarray_fail1.json
|
||||
sv_ap_uarray_fail2 vvp_tests/sv_ap_uarray_fail2.json
|
||||
sv_array_assign_fail1 vvp_tests/sv_array_assign_fail1.json
|
||||
sv_array_assign_fail2 vvp_tests/sv_array_assign_fail2.json
|
||||
sv_array_cassign6 vvp_tests/sv_array_cassign6.json
|
||||
sv_array_cassign7 vvp_tests/sv_array_cassign7.json
|
||||
sv_foreach9 vvp_tests/sv_foreach9.json
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_ap_uarray1.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_ap_uarray2.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_ap_uarray3.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_ap_uarray4.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_ap_uarray5.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_ap_uarray6.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_ap_uarray_fail1.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_ap_uarray_fail2.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_array_assign_fail1.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_array_assign_fail2.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -149,11 +149,10 @@ ivl_type_t NetAssign_::net_type() const
|
|||
} else {
|
||||
ivl_assert(*this, sig_);
|
||||
|
||||
// We don't have types for array signals yet.
|
||||
if (sig_->unpacked_dimensions() && !word_)
|
||||
return nullptr;
|
||||
|
||||
ntype = sig_->net_type();
|
||||
ntype = sig_->array_type();
|
||||
else
|
||||
ntype = sig_->net_type();
|
||||
}
|
||||
|
||||
if (!member_.nil()) {
|
||||
|
|
|
|||
|
|
@ -401,7 +401,13 @@ NetEProperty::NetEProperty(NetNet*net, size_t pidx, NetExpr*idx)
|
|||
ivl_assert(*this, use_type);
|
||||
|
||||
ivl_type_t prop_type = use_type->get_prop_type(pidx_);
|
||||
set_net_type(prop_type);
|
||||
if (idx) {
|
||||
auto array_type = dynamic_cast<const netarray_t*>(prop_type);
|
||||
ivl_assert(*this, array_type);
|
||||
set_net_type(array_type->element_type());
|
||||
} else {
|
||||
set_net_type(prop_type);
|
||||
}
|
||||
}
|
||||
|
||||
NetEProperty::~NetEProperty()
|
||||
|
|
|
|||
11
netlist.cc
11
netlist.cc
|
|
@ -598,6 +598,9 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
|
|||
|
||||
initialize_dir_();
|
||||
|
||||
if (!unpacked_dims_.empty())
|
||||
array_type_ = new netuarray_t(unpacked_dims_, net_type_);
|
||||
|
||||
s->add_signal(this);
|
||||
}
|
||||
|
||||
|
|
@ -733,6 +736,14 @@ const netclass_t* NetNet::class_type(void) const
|
|||
return dynamic_cast<const netclass_t*> (net_type_);
|
||||
}
|
||||
|
||||
const netarray_t* NetNet::array_type() const
|
||||
{
|
||||
if (array_type_)
|
||||
return array_type_;
|
||||
|
||||
return darray_type();
|
||||
}
|
||||
|
||||
/*
|
||||
* "depth" is the number of index expressions that the user is using
|
||||
* to index this identifier. So consider if Net was declared like so:
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ struct enum_type_t;
|
|||
class netclass_t;
|
||||
class netdarray_t;
|
||||
class netparray_t;
|
||||
class netuarray_t;
|
||||
class netqueue_t;
|
||||
class netenum_t;
|
||||
class netstruct_t;
|
||||
|
|
@ -709,6 +710,7 @@ class NetNet : public NetObj, public PortType {
|
|||
const netdarray_t*darray_type(void) const;
|
||||
const netqueue_t*queue_type(void) const;
|
||||
const netclass_t*class_type(void) const;
|
||||
const netarray_t*array_type(void) const;
|
||||
|
||||
/* Attach a discipline to the net. */
|
||||
ivl_discipline_t get_discipline() const;
|
||||
|
|
@ -803,6 +805,7 @@ class NetNet : public NetObj, public PortType {
|
|||
PortType port_type_ : 3;
|
||||
bool local_flag_: 1;
|
||||
ivl_type_t net_type_;
|
||||
netuarray_t *array_type_ = nullptr;
|
||||
ivl_discipline_t discipline_;
|
||||
|
||||
std::vector<netrange_t> unpacked_dims_;
|
||||
|
|
@ -2104,6 +2107,7 @@ class NetEArrayPattern : public NetExpr {
|
|||
NetEArrayPattern* dup_expr() const;
|
||||
NexusSet* nex_input(bool rem_out = true, bool always_sens = false,
|
||||
bool nested_func = false) const;
|
||||
NetNet* synthesize(Design *des, NetScope *scope, NetExpr *root);
|
||||
|
||||
private:
|
||||
std::vector<NetExpr*> items_;
|
||||
|
|
|
|||
18
netmisc.cc
18
netmisc.cc
|
|
@ -986,7 +986,23 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
|
|||
|
||||
ivl_variable_type_t cast_type = ivl_type_base(lv_net_type);
|
||||
ivl_variable_type_t expr_type = tmp->expr_type();
|
||||
if ((cast_type != IVL_VT_NO_TYPE) && (cast_type != expr_type)) {
|
||||
|
||||
bool compatible;
|
||||
// For arrays we need strict type checking here. Long term strict type
|
||||
// checking should be used for all expressions, but at the moment not
|
||||
// all expressions do have a ivl_type_t attached to it.
|
||||
if (dynamic_cast<const netuarray_t*>(lv_net_type)) {
|
||||
if (tmp->net_type())
|
||||
compatible = lv_net_type->type_compatible(tmp->net_type());
|
||||
else
|
||||
compatible = false;
|
||||
} else if (cast_type == IVL_VT_NO_TYPE) {
|
||||
compatible = true;
|
||||
} else {
|
||||
compatible = cast_type == expr_type;
|
||||
}
|
||||
|
||||
if (!compatible) {
|
||||
// Catch some special cases.
|
||||
switch (cast_type) {
|
||||
case IVL_VT_DARRAY:
|
||||
|
|
|
|||
|
|
@ -490,6 +490,58 @@ static void store_vec4_to_lval(ivl_statement_t net)
|
|||
}
|
||||
}
|
||||
|
||||
static unsigned int draw_array_pattern(ivl_signal_t var, ivl_expr_t rval,
|
||||
unsigned int array_idx)
|
||||
{
|
||||
ivl_type_t var_type = ivl_signal_net_type(var);
|
||||
|
||||
for (unsigned int idx = 0; idx < ivl_expr_parms(rval); idx += 1) {
|
||||
ivl_expr_t expr = ivl_expr_parm(rval, idx);
|
||||
|
||||
switch (ivl_expr_type(expr)) {
|
||||
case IVL_EX_ARRAY_PATTERN:
|
||||
/* Flatten nested array patterns */
|
||||
array_idx = draw_array_pattern(var, expr, array_idx);
|
||||
break;
|
||||
default:
|
||||
switch (ivl_type_base(var_type)) {
|
||||
case IVL_VT_BOOL:
|
||||
case IVL_VT_LOGIC:
|
||||
draw_eval_vec4(expr);
|
||||
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", array_idx);
|
||||
fprintf(vvp_out, " %%flag_set/imm 4, 0;\n");
|
||||
fprintf(vvp_out, " %%store/vec4a v%p, 3, 0;\n", var);
|
||||
break;
|
||||
case IVL_VT_REAL:
|
||||
draw_eval_real(expr);
|
||||
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", array_idx);
|
||||
fprintf(vvp_out, " %%flag_set/imm 4, 0;\n");
|
||||
fprintf(vvp_out, " %%store/reala v%p, 3;\n", var);
|
||||
break;
|
||||
case IVL_VT_STRING:
|
||||
draw_eval_string(expr);
|
||||
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", array_idx);
|
||||
fprintf(vvp_out, " %%flag_set/imm 4, 0;\n");
|
||||
fprintf(vvp_out, " %%store/stra v%p, 3;\n", var);
|
||||
break;
|
||||
case IVL_VT_CLASS:
|
||||
draw_eval_object(expr);
|
||||
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", array_idx);
|
||||
fprintf(vvp_out, " %%flag_set/imm 4, 0;\n");
|
||||
fprintf(vvp_out, " %%store/obja v%p, 3;\n", var);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
array_idx++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return array_idx;
|
||||
}
|
||||
|
||||
static int show_stmt_assign_vector(ivl_statement_t net)
|
||||
{
|
||||
ivl_expr_t rval = ivl_stmt_rval(net);
|
||||
|
|
@ -498,6 +550,13 @@ static int show_stmt_assign_vector(ivl_statement_t net)
|
|||
struct vec_slice_info*slices = 0;
|
||||
int idx_reg;
|
||||
|
||||
if (ivl_expr_type(rval) == IVL_EX_ARRAY_PATTERN) {
|
||||
ivl_lval_t lval = ivl_stmt_lval(net, 0);
|
||||
ivl_signal_t sig = ivl_lval_sig(lval);
|
||||
draw_array_pattern(sig, rval, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If this is a compressed assignment, then get the contents
|
||||
of the l-value. We need these values as part of the r-value
|
||||
calculation. */
|
||||
|
|
@ -791,6 +850,13 @@ static int show_stmt_assign_sig_real(ivl_statement_t net)
|
|||
assert(ivl_stmt_lvals(net) == 1);
|
||||
lval = ivl_stmt_lval(net, 0);
|
||||
|
||||
ivl_expr_t rval = ivl_stmt_rval(net);
|
||||
if (ivl_expr_type(rval) == IVL_EX_ARRAY_PATTERN) {
|
||||
ivl_signal_t sig = ivl_lval_sig(lval);
|
||||
draw_array_pattern(sig, rval, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If this is a compressed assignment, then get the contents
|
||||
of the l-value. We need this value as part of the r-value
|
||||
calculation. */
|
||||
|
|
@ -800,7 +866,7 @@ static int show_stmt_assign_sig_real(ivl_statement_t net)
|
|||
get_real_from_lval(lval, slice);
|
||||
}
|
||||
|
||||
draw_eval_real(ivl_stmt_rval(net));
|
||||
draw_eval_real(rval);
|
||||
|
||||
switch (ivl_stmt_opcode(net)) {
|
||||
case 0:
|
||||
|
|
@ -850,6 +916,11 @@ static int show_stmt_assign_sig_string(ivl_statement_t net)
|
|||
assert(ivl_stmt_lvals(net) == 1);
|
||||
assert(ivl_stmt_opcode(net) == 0);
|
||||
|
||||
if (ivl_expr_type(rval) == IVL_EX_ARRAY_PATTERN) {
|
||||
draw_array_pattern(var, rval, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Special case: If the l-value signal (string) is named after
|
||||
its scope, and the scope is a function, then this is an
|
||||
assign to a return value and should be handled
|
||||
|
|
@ -1291,6 +1362,11 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net)
|
|||
}
|
||||
|
||||
} else {
|
||||
if (ivl_expr_type(rval) == IVL_EX_ARRAY_PATTERN) {
|
||||
draw_array_pattern(sig, rval, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* There is no property select, so evaluate the r-value
|
||||
as an object and assign the entire object to the
|
||||
variable. */
|
||||
|
|
|
|||
Loading…
Reference in New Issue