Merge pull request #953 from larsclausen/assign-pattern-uarray

Add initial support for array assignment patterns
This commit is contained in:
Cary R 2023-06-19 00:41:33 -07:00 committed by GitHub
commit df8ac73bba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 668 additions and 25 deletions

View File

@ -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:

View File

@ -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,

View File

@ -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"

View File

@ -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);

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_ap_uarray1.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_ap_uarray2.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_ap_uarray3.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_ap_uarray4.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_ap_uarray5.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_ap_uarray6.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_ap_uarray_fail1.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_ap_uarray_fail2.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_array_assign_fail1.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_array_assign_fail2.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -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()) {

View File

@ -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()

View File

@ -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:

View File

@ -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_;

View File

@ -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:

View File

@ -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. */