From 867c7d18b42af3788f089904bb7f5f131331be72 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 2 Jan 2025 10:36:26 -0800 Subject: [PATCH 1/4] tgt-vvp: Support assignment operators on object properties Currently assignment operators on object properties are silently ignored. Make sure that they are handled. To enable this refactor the code a bit so that the assignment operator handling can be shared between object property assignments and scalar value assignments. Signed-off-by: Lars-Peter Clausen --- tgt-vvp/stmt_assign.c | 282 +++++++++++++++++++++--------------------- 1 file changed, 142 insertions(+), 140 deletions(-) diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index 8c007ac07..7dee5b13c 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -541,13 +541,77 @@ static unsigned int draw_array_pattern(ivl_signal_t var, ivl_expr_t rval, return array_idx; } +static void draw_stmt_assign_vector_opcode(unsigned char opcode, bool is_signed) +{ + int idx_reg; + + switch (opcode) { + case 0: + break; + + case '+': + fprintf(vvp_out, " %%add;\n"); + break; + + case '-': + fprintf(vvp_out, " %%sub;\n"); + break; + + case '*': + fprintf(vvp_out, " %%mul;\n"); + break; + + case '/': + fprintf(vvp_out, " %%div%s;\n", is_signed ? "/s":""); + break; + + case '%': + fprintf(vvp_out, " %%mod%s;\n", is_signed ? "/s":""); + break; + + case '&': + fprintf(vvp_out, " %%and;\n"); + break; + + case '|': + fprintf(vvp_out, " %%or;\n"); + break; + + case '^': + fprintf(vvp_out, " %%xor;\n"); + break; + + case 'l': /* lval <<= expr */ + idx_reg = allocate_word(); + fprintf(vvp_out, " %%ix/vec4 %d;\n", idx_reg); + fprintf(vvp_out, " %%shiftl %d;\n", idx_reg); + clr_word(idx_reg); + break; + + case 'r': /* lval >>= expr */ + idx_reg = allocate_word(); + fprintf(vvp_out, " %%ix/vec4 %d;\n", idx_reg); + fprintf(vvp_out, " %%shiftr %d;\n", idx_reg); + clr_word(idx_reg); + break; + + case 'R': /* lval >>>= expr */ + idx_reg = allocate_word(); + fprintf(vvp_out, " %%ix/vec4 %d;\n", idx_reg); + fprintf(vvp_out, " %%shiftr/s %d;\n", idx_reg); + clr_word(idx_reg); + break; + + default: + fprintf(vvp_out, "; UNSUPPORTED ASSIGNMENT OPCODE: %c\n", opcode); + assert(0); + break; + } +} + static int show_stmt_assign_vector(ivl_statement_t net) { ivl_expr_t rval = ivl_stmt_rval(net); - //struct vector_info res; - //struct vector_info lres = {0, 0}; - 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); @@ -556,96 +620,30 @@ static int show_stmt_assign_vector(ivl_statement_t net) return 0; } + unsigned wid = ivl_stmt_lwidth(net); + /* 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. */ if (ivl_stmt_opcode(net) != 0) { + struct vec_slice_info *slices; + + slices = calloc(ivl_stmt_lvals(net), sizeof(struct vec_slice_info)); + fprintf(vvp_out, " ; show_stmt_assign_vector: Get l-value for compressed %c= operand\n", ivl_stmt_opcode(net)); - slices = calloc(ivl_stmt_lvals(net), sizeof(struct vec_slice_info)); get_vec_from_lval(net, slices); - } - - unsigned wid = ivl_stmt_lwidth(net); - draw_eval_vec4(rval); - resize_vec4_wid(rval, wid); - - switch (ivl_stmt_opcode(net)) { - case 0: + draw_eval_vec4(rval); + resize_vec4_wid(rval, wid); + draw_stmt_assign_vector_opcode(ivl_stmt_opcode(net), + ivl_expr_signed(rval)); + put_vec_to_lval(net, slices); + free(slices); + } else { + draw_eval_vec4(rval); + resize_vec4_wid(rval, wid); store_vec4_to_lval(net); - break; - - case '+': - fprintf(vvp_out, " %%add;\n"); - put_vec_to_lval(net, slices); - break; - - case '-': - fprintf(vvp_out, " %%sub;\n"); - put_vec_to_lval(net, slices); - break; - - case '*': - fprintf(vvp_out, " %%mul;\n"); - put_vec_to_lval(net, slices); - break; - - case '/': - fprintf(vvp_out, " %%div%s;\n", ivl_expr_signed(rval)? "/s":""); - put_vec_to_lval(net, slices); - break; - - case '%': - fprintf(vvp_out, " %%mod%s;\n", ivl_expr_signed(rval)? "/s":""); - put_vec_to_lval(net, slices); - break; - - case '&': - fprintf(vvp_out, " %%and;\n"); - put_vec_to_lval(net, slices); - break; - - case '|': - fprintf(vvp_out, " %%or;\n"); - put_vec_to_lval(net, slices); - break; - - case '^': - fprintf(vvp_out, " %%xor;\n"); - put_vec_to_lval(net, slices); - break; - - case 'l': /* lval <<= expr */ - idx_reg = allocate_word(); - fprintf(vvp_out, " %%ix/vec4 %d;\n", idx_reg); - fprintf(vvp_out, " %%shiftl %d;\n", idx_reg); - clr_word(idx_reg); - put_vec_to_lval(net, slices); - break; - - case 'r': /* lval >>= expr */ - idx_reg = allocate_word(); - fprintf(vvp_out, " %%ix/vec4 %d;\n", idx_reg); - fprintf(vvp_out, " %%shiftr %d;\n", idx_reg); - clr_word(idx_reg); - put_vec_to_lval(net, slices); - break; - - case 'R': /* lval >>>= expr */ - idx_reg = allocate_word(); - fprintf(vvp_out, " %%ix/vec4 %d;\n", idx_reg); - fprintf(vvp_out, " %%shiftr/s %d;\n", idx_reg); - clr_word(idx_reg); - put_vec_to_lval(net, slices); - break; - - default: - fprintf(vvp_out, "; UNSUPPORTED ASSIGNMENT OPCODE: %c\n", ivl_stmt_opcode(net)); - assert(0); - break; } - if (slices) free(slices); - return 0; } @@ -817,42 +815,11 @@ static void store_real_to_lval(ivl_lval_t lval) clr_word(word_ix); } -/* - * This function assigns a value to a real variable. This is destined - * for /dev/null when typed ivl_signal_t takes over all the real - * variable support. - */ -static int show_stmt_assign_sig_real(ivl_statement_t net) +static void draw_stmt_assign_real_opcode(unsigned char opcode) { - struct real_lval_info*slice = 0; - ivl_lval_t lval; - - 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. */ - if (ivl_stmt_opcode(net) != 0) { - fprintf(vvp_out, " ; show_stmt_assign_real: Get l-value for compressed %c= operand\n", ivl_stmt_opcode(net)); - slice = calloc(1, sizeof(struct real_lval_info)); - get_real_from_lval(lval, slice); - } - - draw_eval_real(rval); - - switch (ivl_stmt_opcode(net)) { + switch (opcode) { case 0: - store_real_to_lval(lval); - if (slice) free(slice); - return 0; + break; case '+': fprintf(vvp_out, " %%add/wr;\n"); @@ -875,13 +842,47 @@ static int show_stmt_assign_sig_real(ivl_statement_t net) break; default: - fprintf(vvp_out, "; UNSUPPORTED ASSIGNMENT OPCODE: %c\n", ivl_stmt_opcode(net)); + fprintf(vvp_out, "; UNSUPPORTED ASSIGNMENT OPCODE: %c\n", opcode); assert(0); break; } +} + +/* + * This function assigns a value to a real variable. This is destined + * for /dev/null when typed ivl_signal_t takes over all the real + * variable support. + */ +static int show_stmt_assign_sig_real(ivl_statement_t net) +{ + ivl_lval_t lval; + + 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. */ + if (ivl_stmt_opcode(net) != 0) { + struct real_lval_info slice; + + fprintf(vvp_out, " ; show_stmt_assign_real: Get l-value for compressed %c= operand\n", ivl_stmt_opcode(net)); + get_real_from_lval(lval, &slice); + draw_eval_real(rval); + draw_stmt_assign_real_opcode(ivl_stmt_opcode(net)); + put_real_to_lval(lval, &slice); + } else { + draw_eval_real(rval); + store_real_to_lval(lval); + } - put_real_to_lval(lval, slice); - free(slice); return 0; } @@ -1260,39 +1261,43 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net) ivl_type_t sig_type = ivl_signal_net_type(sig); ivl_type_t prop_type = ivl_type_prop_type(sig_type, prop_idx); - if (ivl_type_base(prop_type) == IVL_VT_BOOL) { + fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); + + if (ivl_type_base(prop_type) == IVL_VT_BOOL || + ivl_type_base(prop_type) == IVL_VT_LOGIC) { assert(ivl_type_packed_dimensions(prop_type) == 0 || (ivl_type_packed_dimensions(prop_type) == 1 && ivl_type_packed_msb(prop_type,0) >= ivl_type_packed_lsb(prop_type, 0))); + if (ivl_stmt_opcode(net) != 0) { + fprintf(vvp_out, " %%prop/v %d;\n", prop_idx); + } + draw_eval_vec4(rval); - if (ivl_expr_value(rval)!=IVL_VT_BOOL) + if (ivl_type_base(prop_type) == IVL_VT_BOOL && + ivl_expr_value(rval) != IVL_VT_BOOL) fprintf(vvp_out, " %%cast2;\n"); - fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); - fprintf(vvp_out, " %%store/prop/v %d, %u; Store in bool property %s\n", - prop_idx, lwid, ivl_type_prop_name(sig_type, prop_idx)); - fprintf(vvp_out, " %%pop/obj 1, 0;\n"); + draw_stmt_assign_vector_opcode(ivl_stmt_opcode(net), + ivl_expr_signed(rval)); - } else if (ivl_type_base(prop_type) == IVL_VT_LOGIC) { - assert(ivl_type_packed_dimensions(prop_type) == 0 || - (ivl_type_packed_dimensions(prop_type) == 1 && - ivl_type_packed_msb(prop_type,0) >= ivl_type_packed_lsb(prop_type, 0))); - - draw_eval_vec4(rval); - - fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); fprintf(vvp_out, " %%store/prop/v %d, %u; Store in logic property %s\n", prop_idx, lwid, ivl_type_prop_name(sig_type, prop_idx)); fprintf(vvp_out, " %%pop/obj 1, 0;\n"); } else if (ivl_type_base(prop_type) == IVL_VT_REAL) { + if (ivl_stmt_opcode(net) != 0) { + fprintf(vvp_out, " %%prop/r %d;\n", prop_idx); + } + /* Calculate the real value into the real value stack. The %store/prop/r will pop the stack value. */ draw_eval_real(rval); - fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); + + draw_stmt_assign_real_opcode(ivl_stmt_opcode(net)); + fprintf(vvp_out, " %%store/prop/r %d;\n", prop_idx); fprintf(vvp_out, " %%pop/obj 1, 0;\n"); @@ -1302,7 +1307,6 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net) stack. The %store/prop/r will pop the stack value. */ draw_eval_string(rval); - fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); fprintf(vvp_out, " %%store/prop/str %d;\n", prop_idx); fprintf(vvp_out, " %%pop/obj 1, 0;\n"); @@ -1313,7 +1317,6 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net) /* The property is a darray, and there is no mux expression to the assignment is of an entire array object. */ - fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); errors += draw_eval_object(rval); fprintf(vvp_out, " %%store/prop/obj %d, %d; IVL_VT_DARRAY\n", prop_idx, idx); fprintf(vvp_out, " %%pop/obj 1, 0;\n"); @@ -1327,7 +1330,6 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net) } /* The property is a class object. */ - fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); errors += draw_eval_object(rval); if (idx_expr) draw_eval_expr_into_integer(idx_expr, idx); fprintf(vvp_out, " %%store/prop/obj %d, %d; IVL_VT_CLASS\n", prop_idx, idx); From 43c138fdd315957616bdaa9dfedac152218a0ca5 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 2 Jan 2025 12:39:35 -0800 Subject: [PATCH 2/4] tgt-vvp: Support assignment operators on queues and dynamic array elements Currently assignment operators on queues and dynamic elements trigger an assert. Add support for handling this properly. Since the operation for loading an element for an queue or dynamic array is identical most of the code can be shared, only writing back the value has to be handled separately. Signed-off-by: Lars-Peter Clausen --- tgt-vvp/stmt_assign.c | 172 +++++++++++++++++++++++++++++------------- 1 file changed, 120 insertions(+), 52 deletions(-) diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index 7dee5b13c..c76954cd0 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -1020,6 +1020,83 @@ static int show_stmt_assign_darray_pattern(ivl_statement_t net) return errors; } +/* + * Loading an element and updating it is identical for queues and dynamic arrays + * and is handled here. The updated value is left on the stack and will be + * written back using type specific functions. + */ +static void show_stmt_assign_sig_darray_queue_mux(ivl_statement_t net) +{ + ivl_lval_t lval = ivl_stmt_lval(net, 0); + ivl_signal_t var = ivl_lval_sig(lval); + ivl_type_t var_type = ivl_signal_net_type(var); + ivl_type_t element_type = ivl_type_element(var_type); + ivl_expr_t mux = ivl_lval_idx(lval); + ivl_expr_t rval = ivl_stmt_rval(net); + + /* + * Queue and dynamic array load and store functions expect the element + * address in index register 3. The index expression must only be + * evaluated once. So in case of an assignment operator it is moved to a + * scratch register and restored to the index register once the rvalue has + * been evaluated. + */ + + switch (ivl_type_base(element_type)) { + case IVL_VT_REAL: + if (ivl_stmt_opcode(net) != 0) { + int mux_word = allocate_word(); + int flag = allocate_flag(); + + draw_eval_expr_into_integer(mux, 3); + fprintf(vvp_out, " %%ix/mov %d, 3;\n", mux_word); + fprintf(vvp_out, " %%flag_mov %u, 4;\n", flag); + fprintf(vvp_out, " %%load/dar/r v%p_0;\n", var); + draw_eval_real(rval); + draw_stmt_assign_real_opcode(ivl_stmt_opcode(net)); + fprintf(vvp_out, " %%flag_mov 4, %d;\n", flag); + fprintf(vvp_out, " %%ix/mov 3, %d;\n", mux_word); + clr_flag(flag); + clr_word(mux_word); + } else { + draw_eval_real(rval); + draw_eval_expr_into_integer(mux, 3); + } + break; + case IVL_VT_STRING: + assert(ivl_stmt_opcode(net) == 0); + draw_eval_string(rval); + break; + case IVL_VT_BOOL: + case IVL_VT_LOGIC: + if (ivl_stmt_opcode(net) != 0) { + int mux_word = allocate_word(); + int flag = allocate_flag(); + + draw_eval_expr_into_integer(mux, 3); + fprintf(vvp_out, " %%ix/mov %d, 3;\n", mux_word); + fprintf(vvp_out, " %%flag_mov %u, 4;\n", flag); + fprintf(vvp_out, " %%load/dar/vec4 v%p_0;\n", var); + draw_eval_vec4(rval); + resize_vec4_wid(rval, ivl_stmt_lwidth(net)); + draw_stmt_assign_vector_opcode(ivl_stmt_opcode(net), + ivl_expr_signed(rval)); + fprintf(vvp_out, " %%flag_mov 4, %d;\n", flag); + fprintf(vvp_out, " %%ix/mov 3, %d;\n", mux_word); + clr_flag(flag); + clr_word(mux_word); + } else { + draw_eval_vec4(rval); + resize_vec4_wid(rval, ivl_stmt_lwidth(net)); + draw_eval_expr_into_integer(mux, 3); + } + break; + default: + assert(0); + break; + } +} + static int show_stmt_assign_sig_darray(ivl_statement_t net) { int errors = 0; @@ -1031,41 +1108,35 @@ static int show_stmt_assign_sig_darray(ivl_statement_t net) assert(ivl_type_base(var_type) == IVL_VT_DARRAY); ivl_type_t element_type = ivl_type_element(var_type); - ivl_expr_t mux = ivl_lval_idx(lval); - assert(ivl_stmt_lvals(net) == 1); - assert(ivl_stmt_opcode(net) == 0); assert(part == 0); - if (mux && (ivl_type_base(element_type) == IVL_VT_REAL)) { - draw_eval_real(rval); - /* The %store/dar/r expects the array index to be in index - register 3. Calculate the index in place. */ - draw_eval_expr_into_integer(mux, 3); - fprintf(vvp_out, " %%store/dar/r v%p_0;\n", var); - - } else if (mux && ivl_type_base(element_type) == IVL_VT_STRING) { - draw_eval_string(rval); - /* The %store/dar/str expects the array index to me in index - register 3. Calculate the index in place. */ - draw_eval_expr_into_integer(mux, 3); - fprintf(vvp_out, " %%store/dar/str v%p_0;\n", var); - - } else if (mux) { - draw_eval_vec4(rval); - resize_vec4_wid(rval, ivl_stmt_lwidth(net)); - /* The %store/dar/vec4 expects the array index to be in index - register 3. Calculate the index in place. */ - draw_eval_expr_into_integer(mux, 3); - fprintf(vvp_out, " %%store/dar/vec4 v%p_0;\n", var); - + if (ivl_lval_idx(lval)) { + show_stmt_assign_sig_darray_queue_mux(net); + switch (ivl_type_base(element_type)) { + case IVL_VT_REAL: + fprintf(vvp_out, " %%store/dar/r v%p_0;\n", var); + break; + case IVL_VT_STRING: + fprintf(vvp_out, " %%store/dar/str v%p_0;\n", var); + break; + case IVL_VT_BOOL: + case IVL_VT_LOGIC: + fprintf(vvp_out, " %%store/dar/vec4 v%p_0;\n", var); + break; + default: + assert(0); + break; + } } else if (ivl_expr_type(rval) == IVL_EX_ARRAY_PATTERN) { + assert(ivl_stmt_opcode(net) == 0); /* There is no l-value mux, but the r-value is an array pattern. This is a special case of an assignment to elements of the l-value. */ errors += show_stmt_assign_darray_pattern(net); } else if (ivl_expr_type(rval) == IVL_EX_NEW) { + assert(ivl_stmt_opcode(net) == 0); // There is no l-value mux, and the r-value expression is // a "new" expression. Handle this by simply storing the // new object to the lval. @@ -1075,6 +1146,7 @@ static int show_stmt_assign_sig_darray(ivl_statement_t net) ivl_signal_basename(var)); } else if (ivl_expr_type(rval) == IVL_EX_SIGNAL) { + assert(ivl_stmt_opcode(net) == 0); // There is no l-value mux, and the r-value expression is // a "signal" expression. Store a duplicate into the lvalue @@ -1088,6 +1160,7 @@ static int show_stmt_assign_sig_darray(ivl_statement_t net) fprintf(vvp_out, " %%pop/obj 1, 0;\n"); } else { + assert(ivl_stmt_opcode(net) == 0); // There is no l-value mux, so this must be an // assignment to the array as a whole. Evaluate the // "object", and store the evaluated result. @@ -1178,10 +1251,7 @@ static int show_stmt_assign_sig_queue(ivl_statement_t net) ivl_type_t var_type= ivl_signal_net_type(var); ivl_type_t element_type = ivl_type_element(var_type); - ivl_expr_t mux = ivl_lval_idx(lval); - assert(ivl_stmt_lvals(net) == 1); - assert(ivl_stmt_opcode(net) == 0); assert(part == 0); assert(ivl_type_base(var_type) == IVL_VT_QUEUE); @@ -1192,41 +1262,39 @@ static int show_stmt_assign_sig_queue(ivl_statement_t net) fprintf(vvp_out, " %%ix/load %d, %u, 0;\n", idx, ivl_signal_array_count(var)); if (ivl_expr_type(rval) == IVL_EX_NULL) { + assert(ivl_stmt_opcode(net) == 0); errors += draw_eval_object(rval); fprintf(vvp_out, " %%store/obj v%p_0;\n", var); - } else if (mux && (ivl_type_base(element_type) == IVL_VT_REAL)) { - draw_eval_real(rval); - /* The %store/qdar expects the array index to be in - index register 3. */ - draw_eval_expr_into_integer(mux, 3); - fprintf(vvp_out, " %%store/qdar/r v%p_0, %d;\n", var, idx); - - } else if (mux && ivl_type_base(element_type) == IVL_VT_STRING) { - draw_eval_string(rval); - /* The %store/qdar expects the array index to be in - index register 3. */ - draw_eval_expr_into_integer(mux, 3); - fprintf(vvp_out, " %%store/qdar/str v%p_0, %d;\n", var, idx); - - } else if (mux) { // What is left must be some form of vector - assert(ivl_type_base(element_type) == IVL_VT_BOOL || - ivl_type_base(element_type) == IVL_VT_LOGIC); - draw_eval_vec4(rval); - resize_vec4_wid(rval, ivl_stmt_lwidth(net)); - /* The %store/qdar expects the array index to be in - index register 3. */ - draw_eval_expr_into_integer(mux, 3); - fprintf(vvp_out, " %%store/qdar/v v%p_0, %d, %u;\n", var, idx, + } else if (ivl_lval_idx(lval)) { + show_stmt_assign_sig_darray_queue_mux(net); + switch (ivl_type_base(element_type)) { + case IVL_VT_REAL: + fprintf(vvp_out, " %%store/qdar/r v%p_0, %d;\n", var, idx); + break; + case IVL_VT_STRING: + fprintf(vvp_out, " %%store/qdar/str v%p_0, %d;\n", var, idx); + break; + case IVL_VT_BOOL: + case IVL_VT_LOGIC: + fprintf(vvp_out, " %%store/qdar/v v%p_0, %d, %u;\n", var, idx, ivl_type_packed_width(element_type)); - + break; + default: + assert(0); + break; + } } else if (ivl_expr_type(rval) == IVL_EX_ARRAY_PATTERN) { + assert(ivl_stmt_opcode(net) == 0); + /* There is no l-value mux, but the r-value is an array pattern. This is a special case of an assignment to the l-value. */ errors += show_stmt_assign_queue_pattern(var, rval, element_type, idx); } else { + assert(ivl_stmt_opcode(net) == 0); + /* There is no l-value mux, so this must be an assignment to the array as a whole. Evaluate the "object", and store the evaluated result. */ From 7c970e91b919b19272f915b5012b9a6cd5eea99a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 3 Jan 2025 12:42:43 -0800 Subject: [PATCH 3/4] Add regression tests for assignment operators on class properties Check that assignment operators are supported for class properties. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/sv_class_prop_assign_op1.v | 58 +++++++++++++++++++ ivtest/ivltests/sv_class_prop_assign_op2.v | 58 +++++++++++++++++++ ivtest/regress-vvp.list | 2 + .../vvp_tests/sv_class_prop_assign_op1.json | 5 ++ .../vvp_tests/sv_class_prop_assign_op2.json | 5 ++ 5 files changed, 128 insertions(+) create mode 100644 ivtest/ivltests/sv_class_prop_assign_op1.v create mode 100644 ivtest/ivltests/sv_class_prop_assign_op2.v create mode 100644 ivtest/vvp_tests/sv_class_prop_assign_op1.json create mode 100644 ivtest/vvp_tests/sv_class_prop_assign_op2.json diff --git a/ivtest/ivltests/sv_class_prop_assign_op1.v b/ivtest/ivltests/sv_class_prop_assign_op1.v new file mode 100644 index 000000000..7d000d7fd --- /dev/null +++ b/ivtest/ivltests/sv_class_prop_assign_op1.v @@ -0,0 +1,58 @@ +// Check that assignment operators are supported on class properties. + +module test; + + bit failed = 1'b0; + + `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) + + class C; + integer x; + endclass + + integer i; + C c; + + initial begin + c = new; + + c.x = 1; + c.x += 5; + `check(c.x, 6); + c.x -= 2; + `check(c.x, 4); + c.x *= 25; + `check(c.x, 100); + c.x /= 5; + `check(c.x, 20); + c.x %= 3; + `check(c.x, 2); + + c.x = 'haa; + c.x &= 'h33; + `check(c.x, 'h22); + c.x |= 'h11; + `check(c.x, 'h33); + c.x ^= 'h22; + `check(c.x, 'h11); + + c.x <<= 3; + `check(c.x, 'h88); + c.x <<<= 1; + `check(c.x, 'h110); + c.x >>= 2; + `check(c.x, 'h44); + c.x >>>= 1; + `check(c.x, 'h22); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_class_prop_assign_op2.v b/ivtest/ivltests/sv_class_prop_assign_op2.v new file mode 100644 index 000000000..a590c45f0 --- /dev/null +++ b/ivtest/ivltests/sv_class_prop_assign_op2.v @@ -0,0 +1,58 @@ +// Check that assignment operators are supported on static class properties. + +module test; + + bit failed = 1'b0; + + `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) + + class C; + static integer x; + endclass + + integer i; + C c; + + initial begin + c = new; + + c.x = 1; + c.x += 5; + `check(c.x, 6); + c.x -= 2; + `check(c.x, 4); + c.x *= 25; + `check(c.x, 100); + c.x /= 5; + `check(c.x, 20); + c.x %= 3; + `check(c.x, 2); + + c.x = 'haa; + c.x &= 'h33; + `check(c.x, 'h22); + c.x |= 'h11; + `check(c.x, 'h33); + c.x ^= 'h22; + `check(c.x, 'h11); + + c.x <<= 3; + `check(c.x, 'h88); + c.x <<<= 1; + `check(c.x, 'h110); + c.x >>= 2; + `check(c.x, 'h44); + c.x >>>= 1; + `check(c.x, 'h22); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 6c05287de..07e2b64a8 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -222,6 +222,8 @@ sv_chained_constructor2 vvp_tests/sv_chained_constructor2.json sv_chained_constructor3 vvp_tests/sv_chained_constructor3.json sv_chained_constructor4 vvp_tests/sv_chained_constructor4.json sv_chained_constructor5 vvp_tests/sv_chained_constructor5.json +sv_class_prop_assign_op1 vvp_tests/sv_class_prop_assign_op1.json +sv_class_prop_assign_op2 vvp_tests/sv_class_prop_assign_op2.json sv_class_prop_logic vvp_tests/sv_class_prop_logic.json sv_const1 vvp_tests/sv_const1.json sv_const2 vvp_tests/sv_const2.json diff --git a/ivtest/vvp_tests/sv_class_prop_assign_op1.json b/ivtest/vvp_tests/sv_class_prop_assign_op1.json new file mode 100644 index 000000000..ce63aecf4 --- /dev/null +++ b/ivtest/vvp_tests/sv_class_prop_assign_op1.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_class_prop_assign_op1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_class_prop_assign_op2.json b/ivtest/vvp_tests/sv_class_prop_assign_op2.json new file mode 100644 index 000000000..9079785f9 --- /dev/null +++ b/ivtest/vvp_tests/sv_class_prop_assign_op2.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_class_prop_assign_op2.v", + "iverilog-args" : [ "-g2005-sv" ] +} From 9f8a8959a75259e899f6b9b94cba78839534043f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 3 Jan 2025 12:28:42 -0800 Subject: [PATCH 4/4] Add regression tests for assignment operators on queue and darray elements Check that assignment operators work as expected on queue and dynamic array elements. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/sv_darray_assign_op.v | 86 +++++++++++++++++++++++ ivtest/ivltests/sv_queue_assign_op.v | 84 ++++++++++++++++++++++ ivtest/regress-vvp.list | 2 + ivtest/vvp_tests/sv_darray_assign_op.json | 5 ++ ivtest/vvp_tests/sv_queue_assign_op.json | 5 ++ tgt-vvp/stmt_assign.c | 1 + 6 files changed, 183 insertions(+) create mode 100644 ivtest/ivltests/sv_darray_assign_op.v create mode 100644 ivtest/ivltests/sv_queue_assign_op.v create mode 100644 ivtest/vvp_tests/sv_darray_assign_op.json create mode 100644 ivtest/vvp_tests/sv_queue_assign_op.json diff --git a/ivtest/ivltests/sv_darray_assign_op.v b/ivtest/ivltests/sv_darray_assign_op.v new file mode 100644 index 000000000..c57818932 --- /dev/null +++ b/ivtest/ivltests/sv_darray_assign_op.v @@ -0,0 +1,86 @@ +// Check that assignment operators are supported on dynamic array elements. + +module test; + + bit failed = 1'b0; + + `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) + + integer x[]; + integer i; + + initial begin + x = new[2]; + + // Static index + x[1] = 1; + x[1] += 5; + `check(x[1], 6); + x[1] -= 2; + `check(x[1], 4); + x[1] *= 25; + `check(x[1], 100); + x[1] /= 5; + `check(x[1], 20); + x[1] %= 3; + `check(x[1], 2); + + x[1] = 'haa; + x[1] &= 'h33; + `check(x[1], 'h22); + x[1] |= 'h11; + `check(x[1], 'h33); + x[1] ^= 'h22; + `check(x[1], 'h11); + + x[1] <<= 3; + `check(x[1], 'h88); + x[1] <<<= 1; + `check(x[1], 'h110); + x[1] >>= 2; + `check(x[1], 'h44); + x[1] >>>= 1; + `check(x[1], 'h22); + + // Dynamic index + x[1] = 1; + i = 1; + x[i] += 5; + `check(x[i], 6); + x[i] -= 2; + `check(x[i], 4); + x[i] *= 25; + `check(x[i], 100); + x[i] /= 5; + `check(x[i], 20); + x[i] %= 3; + `check(x[i], 2); + + x[i] = 'haa; + x[i] &= 'h33; + `check(x[i], 'h22); + x[i] |= 'h11; + `check(x[i], 'h33); + x[i] ^= 'h22; + `check(x[i], 'h11); + + x[i] <<= 3; + `check(x[i], 'h88); + x[i] <<<= 1; + `check(x[i], 'h110); + x[i] >>= 2; + `check(x[i], 'h44); + x[i] >>>= 1; + `check(x[i], 'h22); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_queue_assign_op.v b/ivtest/ivltests/sv_queue_assign_op.v new file mode 100644 index 000000000..c97e9c980 --- /dev/null +++ b/ivtest/ivltests/sv_queue_assign_op.v @@ -0,0 +1,84 @@ +// Check that assignment operators are supported on queue elements. + +module test; + + bit failed = 1'b0; + + `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) + + integer x[$]; + integer i; + + initial begin + x = '{0, 1}; + // Static index + x[1] += 5; + `check(x[1], 6); + x[1] -= 2; + `check(x[1], 4); + x[1] *= 25; + `check(x[1], 100); + x[1] /= 5; + `check(x[1], 20); + x[1] %= 3; + `check(x[1], 2); + + x[1] = 'haa; + x[1] &= 'h33; + `check(x[1], 'h22); + x[1] |= 'h11; + `check(x[1], 'h33); + x[1] ^= 'h22; + `check(x[1], 'h11); + + x[1] <<= 3; + `check(x[1], 'h88); + x[1] <<<= 1; + `check(x[1], 'h110); + x[1] >>= 2; + `check(x[1], 'h44); + x[1] >>>= 1; + `check(x[1], 'h22); + + // Dynamic index + x[1] = 1; + i = 1; + x[i] += 5; + `check(x[i], 6); + x[i] -= 2; + `check(x[i], 4); + x[i] *= 25; + `check(x[i], 100); + x[i] /= 5; + `check(x[i], 20); + x[i] %= 3; + `check(x[i], 2); + + x[i] = 'haa; + x[i] &= 'h33; + `check(x[i], 'h22); + x[i] |= 'h11; + `check(x[i], 'h33); + x[i] ^= 'h22; + `check(x[i], 'h11); + + x[i] <<= 3; + `check(x[i], 'h88); + x[i] <<<= 1; + `check(x[i], 'h110); + x[i] >>= 2; + `check(x[i], 'h44); + x[i] >>>= 1; + `check(x[i], 'h22); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 07e2b64a8..dcba81515 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -239,6 +239,7 @@ sv_const_fail6 vvp_tests/sv_const_fail6.json sv_const_fail7 vvp_tests/sv_const_fail7.json sv_const_fail8 vvp_tests/sv_const_fail8.json sv_const_fail9 vvp_tests/sv_const_fail9.json +sv_darray_assign_op vvp_tests/sv_darray_assign_op.json sv_default_port_value1 vvp_tests/sv_default_port_value1.json sv_default_port_value2 vvp_tests/sv_default_port_value2.json sv_default_port_value3 vvp_tests/sv_default_port_value3.json @@ -257,6 +258,7 @@ sv_module_port2 vvp_tests/sv_module_port2.json sv_module_port3 vvp_tests/sv_module_port3.json sv_module_port4 vvp_tests/sv_module_port4.json sv_parameter_type vvp_tests/sv_parameter_type.json +sv_queue_assign_op vvp_tests/sv_queue_assign_op.json sv_wildcard_import8 vvp_tests/sv_wildcard_import8.json sdf_header vvp_tests/sdf_header.json task_return1 vvp_tests/task_return1.json diff --git a/ivtest/vvp_tests/sv_darray_assign_op.json b/ivtest/vvp_tests/sv_darray_assign_op.json new file mode 100644 index 000000000..065ed73fa --- /dev/null +++ b/ivtest/vvp_tests/sv_darray_assign_op.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_darray_assign_op.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_queue_assign_op.json b/ivtest/vvp_tests/sv_queue_assign_op.json new file mode 100644 index 000000000..b4c2136ec --- /dev/null +++ b/ivtest/vvp_tests/sv_queue_assign_op.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_queue_assign_op.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index c76954cd0..94aed6242 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -1066,6 +1066,7 @@ static void show_stmt_assign_sig_darray_queue_mux(ivl_statement_t net) case IVL_VT_STRING: assert(ivl_stmt_opcode(net) == 0); draw_eval_string(rval); + draw_eval_expr_into_integer(mux, 3); break; case IVL_VT_BOOL: case IVL_VT_LOGIC: