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 <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2025-01-02 10:36:26 -08:00
parent d0327c5eda
commit 867c7d18b4
1 changed files with 142 additions and 140 deletions

View File

@ -541,13 +541,77 @@ static unsigned int draw_array_pattern(ivl_signal_t var, ivl_expr_t rval,
return array_idx; 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) static int show_stmt_assign_vector(ivl_statement_t net)
{ {
ivl_expr_t rval = ivl_stmt_rval(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) { if (ivl_expr_type(rval) == IVL_EX_ARRAY_PATTERN) {
ivl_lval_t lval = ivl_stmt_lval(net, 0); 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; return 0;
} }
unsigned wid = ivl_stmt_lwidth(net);
/* If this is a compressed assignment, then get the contents /* If this is a compressed assignment, then get the contents
of the l-value. We need these values as part of the r-value of the l-value. We need these values as part of the r-value
calculation. */ calculation. */
if (ivl_stmt_opcode(net) != 0) { if (ivl_stmt_opcode(net) != 0) {
fprintf(vvp_out, " ; show_stmt_assign_vector: Get l-value for compressed %c= operand\n", ivl_stmt_opcode(net)); struct vec_slice_info *slices;
slices = calloc(ivl_stmt_lvals(net), sizeof(struct vec_slice_info));
get_vec_from_lval(net, slices);
}
unsigned wid = ivl_stmt_lwidth(net); 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));
get_vec_from_lval(net, slices);
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); draw_eval_vec4(rval);
resize_vec4_wid(rval, wid); resize_vec4_wid(rval, wid);
switch (ivl_stmt_opcode(net)) {
case 0:
store_vec4_to_lval(net); 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; return 0;
} }
@ -817,42 +815,11 @@ static void store_real_to_lval(ivl_lval_t lval)
clr_word(word_ix); clr_word(word_ix);
} }
/* static void draw_stmt_assign_real_opcode(unsigned char opcode)
* 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)
{ {
struct real_lval_info*slice = 0; switch (opcode) {
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)) {
case 0: case 0:
store_real_to_lval(lval); break;
if (slice) free(slice);
return 0;
case '+': case '+':
fprintf(vvp_out, " %%add/wr;\n"); fprintf(vvp_out, " %%add/wr;\n");
@ -875,13 +842,47 @@ static int show_stmt_assign_sig_real(ivl_statement_t net)
break; break;
default: default:
fprintf(vvp_out, "; UNSUPPORTED ASSIGNMENT OPCODE: %c\n", ivl_stmt_opcode(net)); fprintf(vvp_out, "; UNSUPPORTED ASSIGNMENT OPCODE: %c\n", opcode);
assert(0); assert(0);
break; 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; 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 sig_type = ivl_signal_net_type(sig);
ivl_type_t prop_type = ivl_type_prop_type(sig_type, prop_idx); 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 || assert(ivl_type_packed_dimensions(prop_type) == 0 ||
(ivl_type_packed_dimensions(prop_type) == 1 && (ivl_type_packed_dimensions(prop_type) == 1 &&
ivl_type_packed_msb(prop_type,0) >= ivl_type_packed_lsb(prop_type, 0))); 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); 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, " %%cast2;\n");
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); draw_stmt_assign_vector_opcode(ivl_stmt_opcode(net),
fprintf(vvp_out, " %%store/prop/v %d, %u; Store in bool property %s\n", ivl_expr_signed(rval));
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_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", 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)); prop_idx, lwid, ivl_type_prop_name(sig_type, prop_idx));
fprintf(vvp_out, " %%pop/obj 1, 0;\n"); fprintf(vvp_out, " %%pop/obj 1, 0;\n");
} else if (ivl_type_base(prop_type) == IVL_VT_REAL) { } 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 /* Calculate the real value into the real value
stack. The %store/prop/r will pop the stack stack. The %store/prop/r will pop the stack
value. */ value. */
draw_eval_real(rval); 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, " %%store/prop/r %d;\n", prop_idx);
fprintf(vvp_out, " %%pop/obj 1, 0;\n"); 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 stack. The %store/prop/r will pop the stack
value. */ value. */
draw_eval_string(rval); 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, " %%store/prop/str %d;\n", prop_idx);
fprintf(vvp_out, " %%pop/obj 1, 0;\n"); 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 /* The property is a darray, and there is no mux
expression to the assignment is of an entire expression to the assignment is of an entire
array object. */ array object. */
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
errors += draw_eval_object(rval); errors += draw_eval_object(rval);
fprintf(vvp_out, " %%store/prop/obj %d, %d; IVL_VT_DARRAY\n", prop_idx, idx); fprintf(vvp_out, " %%store/prop/obj %d, %d; IVL_VT_DARRAY\n", prop_idx, idx);
fprintf(vvp_out, " %%pop/obj 1, 0;\n"); 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. */ /* The property is a class object. */
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
errors += draw_eval_object(rval); errors += draw_eval_object(rval);
if (idx_expr) draw_eval_expr_into_integer(idx_expr, idx); 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); fprintf(vvp_out, " %%store/prop/obj %d, %d; IVL_VT_CLASS\n", prop_idx, idx);