Merge pull request #1199 from larsclausen/assignment-op

Add support for assignment ops on class properties and dynamic array or queue elements
This commit is contained in:
Lars-Peter Clausen 2025-01-05 16:53:04 -08:00 committed by GitHub
commit b794b9cc26
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 573 additions and 192 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
@ -237,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
@ -255,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

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_class_prop_assign_op1.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_class_prop_assign_op2.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_darray_assign_op.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_queue_assign_op.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -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;
}
@ -1019,6 +1020,84 @@ 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);
draw_eval_expr_into_integer(mux, 3);
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;
@ -1030,41 +1109,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.
@ -1074,6 +1147,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
@ -1087,6 +1161,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.
@ -1177,10 +1252,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);
@ -1191,41 +1263,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. */
@ -1260,39 +1330,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 +1376,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 +1386,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 +1399,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);