diff --git a/elab_expr.cc b/elab_expr.cc index 35e117f11..3f41c32bb 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -91,6 +91,15 @@ static NetBranch* find_existing_implicit_branch(NetNet*sig, NetNet*gnd) return 0; } +NetExpr* elaborate_rval_expr(Design *des, NetScope *scope, ivl_type_t lv_net_type, + PExpr *expr, bool need_const, bool force_unsigned) +{ + return elaborate_rval_expr(des, scope, lv_net_type, + lv_net_type->base_type(), + lv_net_type->packed_width(), + expr, need_const, force_unsigned); +} + NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_type_t lv_net_type, ivl_variable_type_t lv_type, unsigned lv_width, PExpr*expr, bool need_const, bool force_unsigned) @@ -227,13 +236,16 @@ NetExpr*PEAssignPattern::elaborate_expr_darray_(Design*des, NetScope*scope, const netdarray_t*array_type = dynamic_cast (ntype); ivl_assert(*this, array_type); + bool need_const = NEED_CONST & flags; + // This is an array pattern, so run through the elements of // the expression and elaborate each as if they are // element_type expressions. ivl_type_t elem_type = array_type->element_type(); vector elem_exprs (parms_.size()); for (size_t idx = 0 ; idx < parms_.size() ; idx += 1) { - NetExpr*tmp = parms_[idx]->elaborate_expr(des, scope, elem_type, flags); + NetExpr*tmp = elaborate_rval_expr(des, scope, elem_type, + parms_[idx], need_const); elem_exprs[idx] = tmp; } @@ -2009,7 +2021,7 @@ static NetExpr* check_for_enum_methods(const LineInfo*li, NetExpr* count = 0; if (args != 0 && parg) { count = elaborate_rval_expr(des, scope, &netvector_t::atom2u32, - IVL_VT_BOOL, 32, parg); + parg); if (count == 0) { cerr << li->get_fileline() << ": error: unable to elaborate " "enumeration method argument " << use_path << "." @@ -2897,8 +2909,6 @@ unsigned PECallFunction::elaborate_arguments_(Design*des, NetScope*scope, if (tmp) { parms[pidx] = elaborate_rval_expr(des, scope, def->port(pidx)->net_type(), - def->port(pidx)->data_type(), - (unsigned)def->port(pidx)->vector_width(), tmp, need_const); if (parms[pidx] == 0) { parm_errors += 1; @@ -3222,11 +3232,11 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, NetExpr*tmp; tmp = elaborate_rval_expr(des, scope, &netvector_t::atom2u32, - IVL_VT_BOOL, 32, parms_[0], false); + parms_[0], false); sys_expr->parm(1, tmp); tmp = elaborate_rval_expr(des, scope, &netvector_t::atom2u32, - IVL_VT_BOOL, 32, parms_[1], false); + parms_[1], false); sys_expr->parm(2, tmp); return sys_expr; @@ -6546,8 +6556,6 @@ NetExpr* PENewClass::elaborate_expr_constructor_(Design*des, NetScope*scope, PExpr*tmp = parms_[idx-1]; parms[idx] = elaborate_rval_expr(des, scope, def->port(idx)->net_type(), - def->port(idx)->data_type(), - def->port(idx)->vector_width(), tmp, false); if (parms[idx] == 0) parm_errors += 1; diff --git a/elaborate.cc b/elaborate.cc index a5edabd63..1fadc7219 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -140,9 +140,7 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const << ", pin_count=" << lval->pin_count() << endl; } - NetExpr*rval_expr = elaborate_rval_expr(des, scope, lval->net_type(), - lval->data_type(), - lval->vector_width(), pin(1)); + NetExpr*rval_expr = elaborate_rval_expr(des, scope, lval->net_type(), pin(1)); if (rval_expr == 0) { cerr << get_fileline() << ": error: Unable to elaborate r-value: " @@ -3253,8 +3251,6 @@ NetProc* PChainConstructor::elaborate(Design*des, NetScope*scope) const PExpr*tmp = parms_[idx-1]; parms[idx] = elaborate_rval_expr(des, scope, def->port(idx)->net_type(), - def->port(idx)->data_type(), - def->port(idx)->vector_width(), tmp, false); continue; } @@ -4029,7 +4025,7 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope, if (parms_idx < parms_.size() && parms_[parms_idx]) { rv = elaborate_rval_expr(des, scope, port->net_type(), - lv_type, wid, parms_ [parms_idx]); + parms_ [parms_idx]); if (NetEEvent*evt = dynamic_cast (rv)) { cerr << evt->get_fileline() << ": error: An event '" << evt->event()->name() << "' can not be a user " @@ -5172,7 +5168,7 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const // better way to get a reasonable lv_net_type value, and that // probably will involve NetAssign_ having a method for // synthesizing one as needed. - NetExpr*rexp = elaborate_rval_expr(des, scope, 0, ltype, lwid, expr_); + NetExpr*rexp = elaborate_rval_expr(des, scope, lval->net_type(), ltype, lwid, expr_); if (rexp == 0) return 0; @@ -5453,7 +5449,6 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const /* Make the r-value of the initial assignment, and size it properly. Then use it to build the assignment statement. */ initial_expr = elaborate_rval_expr(des, scope, sig->net_type(), - sig->data_type(), sig->vector_width(), expr1_); if (debug_elaborate && initial_expr) { @@ -5700,12 +5695,9 @@ NetProc* PReturn::elaborate(Design*des, NetScope*scope) const NetNet*res = target->find_signal(target->basename()); ivl_assert(*this, res); - ivl_variable_type_t lv_type = res->data_type(); - unsigned long wid = res->vector_width(); NetAssign_*lv = new NetAssign_(res); - NetExpr*val = elaborate_rval_expr(des, scope, res->net_type(), - lv_type, wid, expr_); + NetExpr*val = elaborate_rval_expr(des, scope, res->net_type(), expr_); NetBlock*proc = new NetBlock(NetBlock::SEQU, 0); proc->set_line( *this ); diff --git a/ivtest/ivltests/sv_assign_pattern_cast.v b/ivtest/ivltests/sv_assign_pattern_cast.v new file mode 100644 index 000000000..a01245d3d --- /dev/null +++ b/ivtest/ivltests/sv_assign_pattern_cast.v @@ -0,0 +1,51 @@ +// Check that implicit cast works for expressions in assignment patterns. The +// result should be the same as assigning the expression to a variable with the +// same type as the base type of the assignment pattern target. + +module test; + + int dv[]; + real dr[]; + + int tmpv; + real tmpr; + + bit failed = 1'b0; + + `define check_v(expr) \ + dv = '{expr}; \ + tmpv = expr; \ + if (dv[0] !== tmpv) begin \ + $display("FAILED: `%s`, got %0d, expected %0d", `"expr`", dv[0], tmpv); \ + failed = 1'b1; \ + end + + `define check_r(expr) \ + dr = '{expr}; \ + tmpr = expr; \ + if (dr[0] != tmpr) begin \ + $display("FAILED: `%s`, got %0d, expected %0d", `"expr`", dr[0], tmpr); \ + failed = 1'b1; \ + end + + real r; + int i; + + initial begin + r = 4.56; + i = -11; + + // Implicit cast from real to vector + `check_v(1.234e16) + `check_v(r) + + // Implicit cast from vector to real + `check_r(32'hfffffff0) + `check_r(i) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_assign_pattern_concat.v b/ivtest/ivltests/sv_assign_pattern_concat.v new file mode 100644 index 000000000..e4e51de0f --- /dev/null +++ b/ivtest/ivltests/sv_assign_pattern_concat.v @@ -0,0 +1,34 @@ +// Check that concatenations are evaluated correctly in assignment patterns. +// The result should be the same as assigning the expression to a variable with +// the same type as the base type of the assignment pattern target. + +module test; + + int d[]; + int tmp; + + bit failed = 1'b0; + + `define check(expr) \ + d = '{expr}; \ + tmp = expr; \ + if (d[0] !== tmp) begin \ + $display("FAILED: `%s`, got %0d, expected %0d", `"expr`", d[0], tmp); \ + failed = 1'b1; \ + end + + shortint x; + byte y; + + initial begin + x = -1; + y = 10; + `check({x,y}) + `check({3{y}}) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_assign_pattern_const.v b/ivtest/ivltests/sv_assign_pattern_const.v new file mode 100644 index 000000000..24fbfb4c9 --- /dev/null +++ b/ivtest/ivltests/sv_assign_pattern_const.v @@ -0,0 +1,39 @@ +// Check that named constants can be accessed in assignment patterns. The +// result should be the same as assigning the expression to a variable with the +// same type as the base type of the assignment pattern target. + +module test; + + int d[]; + int tmp; + + bit failed = 1'b0; + + `define check(expr) \ + d = '{expr}; \ + tmp = expr; \ + if (d[0] !== tmp) begin \ + $display("FAILED: `%s`, got %0d, expected %0d", `"expr`", d[0], tmp); \ + failed = 1'b1; \ + end + + parameter A = -1; + localparam B = 10; + + typedef enum { + X = -1, Y = 0, Z = 1 + } T; + + initial begin + `check(A) + `check(B) + `check(X) + `check(Y) + `check(Z) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_assign_pattern_expand.v b/ivtest/ivltests/sv_assign_pattern_expand.v new file mode 100644 index 000000000..4d0a2d25f --- /dev/null +++ b/ivtest/ivltests/sv_assign_pattern_expand.v @@ -0,0 +1,45 @@ +// Check that the width of the element type of the target of an assignment +// pattern is considered when evaluating the expression. The result should be +// the same as assigning the expression to a variable with the same type as the +// base type of the assignment pattern target. + +module test; + + int d[]; + int tmp; + + bit failed = 1'b0; + + `define check(expr) \ + d = '{expr}; \ + tmp = expr; \ + if (d[0] !== tmp) begin \ + $display("FAILED: `%s`, got %0d, expected %0d", `"expr`", d[0], tmp); \ + failed = 1'b1; \ + end + + shortint x; + bit [7:0] y; + + initial begin + x = -11; + y = 8'h80; + + // Sign extension + `check(x) + `check(16'sh8000) + + // No sign extension + `check(8'hff) + `check(y) + + // Gets evaluated in a 32 bit context, the result is 2/-2 not 0 + `check(1'b1 + 1'b1) + `check(1'sb1 + 1'sb1) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_assign_pattern_func.v b/ivtest/ivltests/sv_assign_pattern_func.v new file mode 100644 index 000000000..02e682499 --- /dev/null +++ b/ivtest/ivltests/sv_assign_pattern_func.v @@ -0,0 +1,40 @@ +// Check that function calls within an assignment pattern are evaluated +// correctly. The result should be the same as assigning the expression to a +// variable with the same type as the base type of the assignment pattern +// target. + + +module test; + + int d[]; + int tmp; + + bit failed = 1'b0; + + `define check(expr) \ + d = '{expr}; \ + tmp = expr; \ + if (d[0] !== tmp) begin \ + $display("FAILED: `%s`, got %0d, expected %0d", `"expr`", d[0], tmp); \ + failed = 1'b1; \ + end + + int x, y; + + function int fn(int x); + return x*2; + endfunction + + initial begin + x = -3; + y = 10; + + `check(fn(x)) + `check($clog2(y)) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_assign_pattern_op.v b/ivtest/ivltests/sv_assign_pattern_op.v new file mode 100644 index 000000000..d73ad85e0 --- /dev/null +++ b/ivtest/ivltests/sv_assign_pattern_op.v @@ -0,0 +1,73 @@ +// Check that operators in an assignment pattern are evaluated correctly. The +// result should be the same as assigning the expression to a variable with the +// same type as the base type of the assignment pattern target. + +module test; + + int d[]; + int tmp; + + bit failed = 1'b0; + + `define check(expr) \ + d = '{expr}; \ + tmp = expr; \ + if (d[0] !== tmp) begin \ + $display("FAILED: `%s`, got %0d, expected %0d", `"expr`", d[0], tmp); \ + failed = 1'b1; \ + end + + int x, y; + + initial begin + x = -2; + y = 5; + + `check(+x); + `check(-x); + `check(!x); + `check(~x); + `check(&x); + `check(~&x); + `check(|x); + `check(~|x); + `check(^x); + `check(~^x); + + `check(x + y) + `check(x - y) + `check(x * y) + `check(x / y) + `check(x % y) + `check(x ** y) + + `check(x & y) + `check(x | y) + `check(x ^ y) + `check(x ^~ y) + + `check(x >> y); + `check(x << y); + `check(x >>> y); + `check(x <<< y); + + `check(x == y); + `check(x != y); + `check(x === y); + `check(x !== y); + `check(x < y); + `check(x <= y); + `check(x > y); + `check(x >= y); + + `check(x && y); + `check(x || y); + + `check(x ? x : y); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_assign_pattern_part.v b/ivtest/ivltests/sv_assign_pattern_part.v new file mode 100644 index 000000000..957aedd6a --- /dev/null +++ b/ivtest/ivltests/sv_assign_pattern_part.v @@ -0,0 +1,37 @@ +// Check that part selects are evaluated correctly within assignment patterns. +// The result should be the same as assigning the expression to a variable with +// the same type as the base type of the assignment pattern target. + +module test; + + int d[]; + int tmp; + + bit failed = 1'b0; + + `define check(expr) \ + d = '{expr}; \ + tmp = expr; \ + if (d[0] !== tmp) begin \ + $display("FAILED: `%s`, got %0d, expected %0d", `"expr`", d[0], tmp); \ + failed = 1'b1; \ + end + + logic [23:0] x; + int i = 13; + + initial begin + x = 24'ha5a5a5; + `check(x[0]) + `check(x[7:0]) + `check(x[3+:8]) + `check(x[23-:5]) + `check(x[i+:8]) + `check(x[i-:5]) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/regress-sv.list b/ivtest/regress-sv.list index 06b392d6e..5e10030ab 100644 --- a/ivtest/regress-sv.list +++ b/ivtest/regress-sv.list @@ -455,6 +455,13 @@ struct_packed_write_read2 normal,-g2009 ivltests struct_invalid_member CE,-g2009 ivltests gold=struct_invalid_member.gold struct_signed normal,-g2009 ivltests sv-constants normal,-g2005-sv ivltests +sv_assign_pattern_cast normal,-g2005-sv ivltests +sv_assign_pattern_const normal,-g2005-sv ivltests +sv_assign_pattern_concat normal,-g2005-sv ivltests +sv_assign_pattern_expand normal,-g2005-sv ivltests +sv_assign_pattern_func normal,-g2005-sv ivltests +sv_assign_pattern_op normal,-g2005-sv ivltests +sv_assign_pattern_part normal,-g2005-sv ivltests sv_array_assign_pattern2 normal,-g2009 ivltests sv_cast_integer normal,-g2005-sv ivltests sv_cast_integer2 normal,-g2005-sv ivltests diff --git a/ivtest/regress-vlog95.list b/ivtest/regress-vlog95.list index 3f9b3d29b..ddf6e57f6 100644 --- a/ivtest/regress-vlog95.list +++ b/ivtest/regress-vlog95.list @@ -315,6 +315,13 @@ br_gh383c CE,-g2012,-pallowsigned=1 ivltests br_gh383d CE,-g2012,-pallowsigned=1 ivltests br_gh460 CE,-g2012 ivltests br_ml20191221 CE,-g2009,-pallowsigned=1 ivltests +sv_assign_pattern_cast CE,-g2005-sv,-pallowsigned=1 ivltests +sv_assign_pattern_const CE,-g2005-sv,-pallowsigned=1 ivltests +sv_assign_pattern_concat CE,-g2005-sv,-pallowsigned=1 ivltests +sv_assign_pattern_expand CE,-g2005,-sv-pallowsigned=1 ivltests +sv_assign_pattern_func CE,-g2005-sv,-pallowsigned=1 ivltests +sv_assign_pattern_op CE,-g2005-sv,-pallowsigned=1 ivltests +sv_assign_pattern_part CE,-g2005-sv,-pallowsigned=1 ivltests sv_array_assign_pattern2 CE,-g2009,-pallowsigned=1 ivltests sv_cast_darray CE,-g2005-sv,-pallowsigned=1 ivltests sv_darray1 CE,-g2009,-pallowsigned=1 ivltests diff --git a/netmisc.h b/netmisc.h index 17f3d20b9..621a95757 100644 --- a/netmisc.h +++ b/netmisc.h @@ -408,6 +408,13 @@ extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, unsigned lv_width, PExpr*expr, bool need_const =false, bool force_unsigned =false); +/* + * Same as above, but lv_width and lv_type are derived from the lv_net_type. + */ +extern NetExpr* elaborate_rval_expr(Design *des, NetScope *scope, + ivl_type_t lv_net_type, PExpr *expr, + bool need_const = false, + bool force_unsigned = false); extern bool evaluate_range(Design*des, NetScope*scope, const LineInfo*li, const pform_range_t&range, diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index c467f983e..7eb98d7de 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -968,18 +968,21 @@ static int show_stmt_assign_darray_pattern(ivl_statement_t net) case IVL_VT_LOGIC: draw_eval_vec4(ivl_expr_parm(rval,idx)); fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx); + fprintf(vvp_out, " %%flag_set/imm 4, 0;\n"); fprintf(vvp_out, " %%store/dar/vec4 v%p_0;\n", var); break; case IVL_VT_REAL: draw_eval_real(ivl_expr_parm(rval,idx)); fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx); + fprintf(vvp_out, " %%flag_set/imm 4, 0;\n"); fprintf(vvp_out, " %%store/dar/r v%p_0;\n", var); break; case IVL_VT_STRING: draw_eval_string(ivl_expr_parm(rval,idx)); fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx); + fprintf(vvp_out, " %%flag_set/imm 4, 0;\n"); fprintf(vvp_out, " %%store/dar/str v%p_0;\n", var); break; @@ -1102,6 +1105,7 @@ static int show_stmt_assign_queue_pattern(ivl_signal_t var, ivl_expr_t rval, case IVL_VT_LOGIC: draw_eval_vec4(ivl_expr_parm(rval,idx)); fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx); + fprintf(vvp_out, " %%flag_set/imm 4, 0;\n"); fprintf(vvp_out, " %%store/qdar/v v%p_0, %d, %u;\n", var, max_idx, width_of_packed_type(element_type)); break; @@ -1109,12 +1113,14 @@ static int show_stmt_assign_queue_pattern(ivl_signal_t var, ivl_expr_t rval, case IVL_VT_REAL: draw_eval_real(ivl_expr_parm(rval,idx)); fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx); + fprintf(vvp_out, " %%flag_set/imm 4, 0;\n"); fprintf(vvp_out, " %%store/qdar/r v%p_0, %d;\n", var, max_idx); break; case IVL_VT_STRING: draw_eval_string(ivl_expr_parm(rval,idx)); fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx); + fprintf(vvp_out, " %%flag_set/imm 4, 0;\n"); fprintf(vvp_out, " %%store/qdar/str v%p_0, %d;\n", var, max_idx); break;