diff --git a/PExpr.h b/PExpr.h index c55f0d521b..b91e9bdcf2 100644 --- a/PExpr.h +++ b/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 &dims, + unsigned int cur_dim, bool need_const) const; private: diff --git a/elab_expr.cc b/elab_expr.cc index 1758427df2..fa3d3f87d7 100644 --- a/elab_expr.cc +++ b/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(lv_net_type)) + typed_elab = true; + // Special case, PEAssignPattern is context dependend on the type and // always uses the typed elaboration if (dynamic_cast(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(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(ntype)) { + return elaborate_expr_uarray_(des, scope, uarray_type, + uarray_type->static_dimensions(), 0, + need_const); + } if (auto parray_type = dynamic_cast(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 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 &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 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(parms_[idx])) { + expr = ap->elaborate_expr_uarray_(des, scope, uarray_type, + dims, cur_dim, need_const); + } else if (dynamic_cast(parms_[idx])) { + cerr << get_fileline() << ": sorry: " + << "Array concatenation is not yet supported." + << endl; + des->errors++; + } else if (dynamic_cast(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, diff --git a/elab_lval.cc b/elab_lval.cc index 96fdd011e4..74c28267e7 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -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" diff --git a/elaborate.cc b/elaborate.cc index 1d21002da7..0ee0656c4c 100644 --- a/elaborate.cc +++ b/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 (expr); if (!ident) { - des->errors++; if (dynamic_cast (expr)) { cout << loc.get_fileline() << ": sorry: Continuous assignment" << " of array concatenation is not yet supported." << endl; + des->errors++; + return nullptr; } else if (dynamic_cast (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() = " << 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); diff --git a/expr_synth.cc b/expr_synth.cc index cc626277ee..f8105e679c 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -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(net_type()); + ivl_assert(*this, array_type); + + if (items_.empty()) + return nullptr; + + bool failed = false; + + std::unique_ptr 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 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(); diff --git a/ivtest/ivltests/sv_ap_uarray1.v b/ivtest/ivltests/sv_ap_uarray1.v new file mode 100644 index 0000000000..b8279dd6a9 --- /dev/null +++ b/ivtest/ivltests/sv_ap_uarray1.v @@ -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 diff --git a/ivtest/ivltests/sv_ap_uarray2.v b/ivtest/ivltests/sv_ap_uarray2.v new file mode 100644 index 0000000000..96d6befed1 --- /dev/null +++ b/ivtest/ivltests/sv_ap_uarray2.v @@ -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 diff --git a/ivtest/ivltests/sv_ap_uarray3.v b/ivtest/ivltests/sv_ap_uarray3.v new file mode 100644 index 0000000000..e225cbd53b --- /dev/null +++ b/ivtest/ivltests/sv_ap_uarray3.v @@ -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 diff --git a/ivtest/ivltests/sv_ap_uarray4.v b/ivtest/ivltests/sv_ap_uarray4.v new file mode 100644 index 0000000000..14de755f8f --- /dev/null +++ b/ivtest/ivltests/sv_ap_uarray4.v @@ -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 diff --git a/ivtest/ivltests/sv_ap_uarray5.v b/ivtest/ivltests/sv_ap_uarray5.v new file mode 100644 index 0000000000..5c29b94d81 --- /dev/null +++ b/ivtest/ivltests/sv_ap_uarray5.v @@ -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 diff --git a/ivtest/ivltests/sv_ap_uarray6.v b/ivtest/ivltests/sv_ap_uarray6.v new file mode 100644 index 0000000000..870cfe8eea --- /dev/null +++ b/ivtest/ivltests/sv_ap_uarray6.v @@ -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 diff --git a/ivtest/ivltests/sv_ap_uarray_fail1.v b/ivtest/ivltests/sv_ap_uarray_fail1.v new file mode 100644 index 0000000000..5229337fe0 --- /dev/null +++ b/ivtest/ivltests/sv_ap_uarray_fail1.v @@ -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 diff --git a/ivtest/ivltests/sv_ap_uarray_fail2.v b/ivtest/ivltests/sv_ap_uarray_fail2.v new file mode 100644 index 0000000000..c950357f03 --- /dev/null +++ b/ivtest/ivltests/sv_ap_uarray_fail2.v @@ -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 diff --git a/ivtest/ivltests/sv_array_assign_fail1.v b/ivtest/ivltests/sv_array_assign_fail1.v new file mode 100644 index 0000000000..be96017852 --- /dev/null +++ b/ivtest/ivltests/sv_array_assign_fail1.v @@ -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 diff --git a/ivtest/ivltests/sv_array_assign_fail2.v b/ivtest/ivltests/sv_array_assign_fail2.v new file mode 100644 index 0000000000..ab7fc60261 --- /dev/null +++ b/ivtest/ivltests/sv_array_assign_fail2.v @@ -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 diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 9ed96d87be..41501aaa6f 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -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 diff --git a/ivtest/vvp_tests/sv_ap_uarray1.json b/ivtest/vvp_tests/sv_ap_uarray1.json new file mode 100644 index 0000000000..d16e847dcc --- /dev/null +++ b/ivtest/vvp_tests/sv_ap_uarray1.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_ap_uarray1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_ap_uarray2.json b/ivtest/vvp_tests/sv_ap_uarray2.json new file mode 100644 index 0000000000..2ff7359ffb --- /dev/null +++ b/ivtest/vvp_tests/sv_ap_uarray2.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_ap_uarray2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_ap_uarray3.json b/ivtest/vvp_tests/sv_ap_uarray3.json new file mode 100644 index 0000000000..3305072e6a --- /dev/null +++ b/ivtest/vvp_tests/sv_ap_uarray3.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_ap_uarray3.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_ap_uarray4.json b/ivtest/vvp_tests/sv_ap_uarray4.json new file mode 100644 index 0000000000..91c883de0e --- /dev/null +++ b/ivtest/vvp_tests/sv_ap_uarray4.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_ap_uarray4.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_ap_uarray5.json b/ivtest/vvp_tests/sv_ap_uarray5.json new file mode 100644 index 0000000000..a48c75deaa --- /dev/null +++ b/ivtest/vvp_tests/sv_ap_uarray5.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_ap_uarray5.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_ap_uarray6.json b/ivtest/vvp_tests/sv_ap_uarray6.json new file mode 100644 index 0000000000..118e64dea3 --- /dev/null +++ b/ivtest/vvp_tests/sv_ap_uarray6.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_ap_uarray6.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_ap_uarray_fail1.json b/ivtest/vvp_tests/sv_ap_uarray_fail1.json new file mode 100644 index 0000000000..594e06961d --- /dev/null +++ b/ivtest/vvp_tests/sv_ap_uarray_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_ap_uarray_fail1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_ap_uarray_fail2.json b/ivtest/vvp_tests/sv_ap_uarray_fail2.json new file mode 100644 index 0000000000..4b8648f6f3 --- /dev/null +++ b/ivtest/vvp_tests/sv_ap_uarray_fail2.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_ap_uarray_fail2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_array_assign_fail1.json b/ivtest/vvp_tests/sv_array_assign_fail1.json new file mode 100644 index 0000000000..a6a36932a7 --- /dev/null +++ b/ivtest/vvp_tests/sv_array_assign_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_array_assign_fail1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_array_assign_fail2.json b/ivtest/vvp_tests/sv_array_assign_fail2.json new file mode 100644 index 0000000000..c90a0b9d88 --- /dev/null +++ b/ivtest/vvp_tests/sv_array_assign_fail2.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_array_assign_fail2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/net_assign.cc b/net_assign.cc index a6608320ee..e47010df9c 100644 --- a/net_assign.cc +++ b/net_assign.cc @@ -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()) { diff --git a/net_expr.cc b/net_expr.cc index 1b0c5ec270..6460302fb8 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -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(prop_type); + ivl_assert(*this, array_type); + set_net_type(array_type->element_type()); + } else { + set_net_type(prop_type); + } } NetEProperty::~NetEProperty() diff --git a/netlist.cc b/netlist.cc index 239f7004fd..1fdd07606a 100644 --- a/netlist.cc +++ b/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 (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: diff --git a/netlist.h b/netlist.h index 85814c1d3b..5953d20484 100644 --- a/netlist.h +++ b/netlist.h @@ -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 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 items_; diff --git a/netmisc.cc b/netmisc.cc index fbcc0ccc4d..5954db89fa 100644 --- a/netmisc.cc +++ b/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(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: diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index 6e818acff8..83bcd7df30 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -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. */