From bc3cb04a413f6302e282cdeab71a42885fdb6d1f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 17 Jun 2023 11:36:06 -0700 Subject: [PATCH 1/5] Set correct type for indexed array properties For indexed array properties the type of the expression is the type of the element. Signed-off-by: Lars-Peter Clausen --- net_expr.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net_expr.cc b/net_expr.cc index 1b0c5ec27..6460302fb 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() From 4defb9f51ee2865d72615f935e2440e4372e0648 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 4 Feb 2023 21:18:13 -0800 Subject: [PATCH 2/5] Provide type for array signals Types for array signals are currently handled as a special case. The type that is associated with the signal is not the array type itself but rather the element type. There is a fair amount of existing code that depends on this behavior so it is not trivial to change this. But there are certain constructs such as assignment patterns or array concatenation where the array type itself is required. Add a new `NetNet::array_type()` method that will return the array type if the signal is an array. This will allow to query the array type when needed. `NetAssign_::net_type()` is updated to use this new method to return the array type if the assigned signal is an array. Long term the special handling of arrays for signals should be removed. This will for example allow to unify the handling of arrays for signals, class properties and struct members. Signed-off-by: Lars-Peter Clausen --- net_assign.cc | 7 +++---- netlist.cc | 11 +++++++++++ netlist.h | 2 ++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/net_assign.cc b/net_assign.cc index a6608320e..e47010df9 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/netlist.cc b/netlist.cc index 239f7004f..1fdd07606 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 85814c1d3..61163d66e 100644 --- a/netlist.h +++ b/netlist.h @@ -709,6 +709,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 +804,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_; From 9549156226097215ba6079e8228400470a3ab612 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 17 Jun 2023 11:07:33 -0700 Subject: [PATCH 3/5] Add initial support for array assignment patterns SystemVerilog allows to use assignment patterns to assign values to an array. E.g. `int a[4] = '{1, 2, 3, 4}`. Each value is evaluated in the context of the element type of the array. Nested assignment patterns are supported. E.g. `int a[2][2] = '{'{1, 2}, '{1, 2}};` Add initial support for array assignment patterns for both continuous as well as procedural assignments. For continuous assignments the assignment pattern is synthesized into an array of nets. Each pin is connected to one of the assignment pattern values and then the whole net array is connected to target array. For procedural assignments it is unrolled in the vvp backend. E.g effectively turning `a = '{1, 2};` into `a[0] = 1; a[1] = 2;`. Not yet supported are indexed initializers or `default`. E.g. `int a[10] = '{1:10, default: 20};` Signed-off-by: Lars-Peter Clausen --- PExpr.h | 9 +++- elab_expr.cc | 97 +++++++++++++++++++++++++++++++++++++++---- elab_lval.cc | 8 +++- elaborate.cc | 19 +++++---- expr_synth.cc | 53 +++++++++++++++++++++++ netlist.h | 2 + netmisc.cc | 18 +++++++- tgt-vvp/stmt_assign.c | 78 +++++++++++++++++++++++++++++++++- 8 files changed, 264 insertions(+), 20 deletions(-) diff --git a/PExpr.h b/PExpr.h index c55f0d521..b91e9bdcf 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 1758427df..fa3d3f87d 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 96fdd011e..74c28267e 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 1d21002da..0ee0656c4 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 cc626277e..f8105e679 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/netlist.h b/netlist.h index 61163d66e..5953d2048 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; @@ -2106,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 fbcc0ccc4..5954db89f 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 6e818acff..83bcd7df3 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. */ From 90a1168086a45b319f1aa75e7655982e93d69d5f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 4 Jun 2023 16:02:31 -0700 Subject: [PATCH 4/5] Add regression tests for unpacked array assignment patterns Check that basic assignment patterns are supported for unpacked arrays. Check that all of packed types, reals and string arrays are supported. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/sv_ap_uarray1.v | 44 +++++++++++++++++++++++ ivtest/ivltests/sv_ap_uarray2.v | 45 ++++++++++++++++++++++++ ivtest/ivltests/sv_ap_uarray3.v | 44 +++++++++++++++++++++++ ivtest/ivltests/sv_ap_uarray4.v | 45 ++++++++++++++++++++++++ ivtest/ivltests/sv_ap_uarray5.v | 45 ++++++++++++++++++++++++ ivtest/ivltests/sv_ap_uarray6.v | 45 ++++++++++++++++++++++++ ivtest/ivltests/sv_ap_uarray_fail1.v | 13 +++++++ ivtest/ivltests/sv_ap_uarray_fail2.v | 13 +++++++ ivtest/regress-vvp.list | 8 +++++ ivtest/vvp_tests/sv_ap_uarray1.json | 5 +++ ivtest/vvp_tests/sv_ap_uarray2.json | 5 +++ ivtest/vvp_tests/sv_ap_uarray3.json | 5 +++ ivtest/vvp_tests/sv_ap_uarray4.json | 5 +++ ivtest/vvp_tests/sv_ap_uarray5.json | 5 +++ ivtest/vvp_tests/sv_ap_uarray6.json | 5 +++ ivtest/vvp_tests/sv_ap_uarray_fail1.json | 5 +++ ivtest/vvp_tests/sv_ap_uarray_fail2.json | 5 +++ 17 files changed, 342 insertions(+) create mode 100644 ivtest/ivltests/sv_ap_uarray1.v create mode 100644 ivtest/ivltests/sv_ap_uarray2.v create mode 100644 ivtest/ivltests/sv_ap_uarray3.v create mode 100644 ivtest/ivltests/sv_ap_uarray4.v create mode 100644 ivtest/ivltests/sv_ap_uarray5.v create mode 100644 ivtest/ivltests/sv_ap_uarray6.v create mode 100644 ivtest/ivltests/sv_ap_uarray_fail1.v create mode 100644 ivtest/ivltests/sv_ap_uarray_fail2.v create mode 100644 ivtest/vvp_tests/sv_ap_uarray1.json create mode 100644 ivtest/vvp_tests/sv_ap_uarray2.json create mode 100644 ivtest/vvp_tests/sv_ap_uarray3.json create mode 100644 ivtest/vvp_tests/sv_ap_uarray4.json create mode 100644 ivtest/vvp_tests/sv_ap_uarray5.json create mode 100644 ivtest/vvp_tests/sv_ap_uarray6.json create mode 100644 ivtest/vvp_tests/sv_ap_uarray_fail1.json create mode 100644 ivtest/vvp_tests/sv_ap_uarray_fail2.json diff --git a/ivtest/ivltests/sv_ap_uarray1.v b/ivtest/ivltests/sv_ap_uarray1.v new file mode 100644 index 000000000..b8279dd6a --- /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 000000000..96d6befed --- /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 000000000..e225cbd53 --- /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 000000000..14de755f8 --- /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 000000000..5c29b94d8 --- /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 000000000..870cfe8ee --- /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 000000000..5229337fe --- /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 000000000..c950357f0 --- /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/regress-vvp.list b/ivtest/regress-vvp.list index 9ed96d87b..e4bca4a36 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -45,6 +45,14 @@ 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_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 000000000..d16e847dc --- /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 000000000..2ff7359ff --- /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 000000000..3305072e6 --- /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 000000000..91c883de0 --- /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 000000000..a48c75dea --- /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 000000000..118e64dea --- /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 000000000..594e06961 --- /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 000000000..4b8648f6f --- /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" ] +} From 6991b2d84feb2da2772491092aa065126e2ac8fa Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 17 Jun 2023 11:58:59 -0700 Subject: [PATCH 5/5] Add regression tests for assigning scalar value to array Check that trying to assign a scalar value to an array results in an error. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/sv_array_assign_fail1.v | 13 +++++++++++++ ivtest/ivltests/sv_array_assign_fail2.v | 14 ++++++++++++++ ivtest/regress-vvp.list | 2 ++ ivtest/vvp_tests/sv_array_assign_fail1.json | 5 +++++ ivtest/vvp_tests/sv_array_assign_fail2.json | 5 +++++ 5 files changed, 39 insertions(+) create mode 100644 ivtest/ivltests/sv_array_assign_fail1.v create mode 100644 ivtest/ivltests/sv_array_assign_fail2.v create mode 100644 ivtest/vvp_tests/sv_array_assign_fail1.json create mode 100644 ivtest/vvp_tests/sv_array_assign_fail2.json diff --git a/ivtest/ivltests/sv_array_assign_fail1.v b/ivtest/ivltests/sv_array_assign_fail1.v new file mode 100644 index 000000000..be9601785 --- /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 000000000..ab7fc6026 --- /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 e4bca4a36..41501aaa6 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -53,6 +53,8 @@ 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_array_assign_fail1.json b/ivtest/vvp_tests/sv_array_assign_fail1.json new file mode 100644 index 000000000..a6a36932a --- /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 000000000..c90a0b9d8 --- /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" ] +}