diff --git a/src/V3Task.cpp b/src/V3Task.cpp index dfa248f84..620f5d4be 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -508,6 +508,16 @@ class TaskVisitor final : public VNVisitor { return assp; } + void changeAtWriteRecurse(AstNodeExpr* const exprp) { + // Change nested at methods to writable variant + if (AstCMethodHard* const cMethodp = VN_CAST(exprp, CMethodHard)) { + if (cMethodp->method() == VCMethod::ARRAY_AT) { + cMethodp->method(VCMethod::ARRAY_AT_WRITE); + } + changeAtWriteRecurse(cMethodp->fromp()); + } + } + void connectPort(AstVar* portp, AstArg* argp, const string& namePrefix, AstNode* beginp, bool inlineTask) { AstNodeExpr* const pinp = argp->exprp(); @@ -538,10 +548,7 @@ class TaskVisitor final : public VNVisitor { refArgOk = cMethodp->method() == VCMethod::DYN_AT_WRITE_APPEND || cMethodp->method() == VCMethod::DYN_AT_WRITE_APPEND_BACK; } else { - if (cMethodp->method() == VCMethod::ARRAY_AT) { - // Change the method to writable variant - cMethodp->method(VCMethod::ARRAY_AT_WRITE); - } + changeAtWriteRecurse(cMethodp); refArgOk = cMethodp->method() == VCMethod::ARRAY_AT_WRITE; } } diff --git a/test_regress/t/t_func_ref_arg.v b/test_regress/t/t_func_ref_arg.v index 159bacbcf..29abf15fb 100644 --- a/test_regress/t/t_func_ref_arg.v +++ b/test_regress/t/t_func_ref_arg.v @@ -28,10 +28,16 @@ class Cls; endfunction endclass +typedef struct { + MyInt arr[2][][$]; +} struct_t; + module t; int a, b; int arr[1]; int dyn_arr[]; + int dyn_arr_2d[][]; + struct_t st; Cls cls; MyInt mi; initial begin @@ -64,6 +70,25 @@ module t; `checkh(dyn_arr[1], 2); `checkh(b, 5); + dyn_arr_2d = new[2]; + dyn_arr_2d[0] = new[4]; + dyn_arr_2d[0][1] = 10; + b = get_val_set_5(dyn_arr_2d[0][1]); + `checkh(dyn_arr_2d[0][1], 5); + `checkh(b, 10); + b = cls.get_val_set_2(dyn_arr_2d[0][1]); + `checkh(dyn_arr_2d[0][1], 2); + `checkh(b, 5); + + st.arr[1] = new[3]; + st.arr[1][2][0] = new(10); + b = get_val_set_5(st.arr[1][2][0].x); + `checkh(st.arr[1][2][0].x, 5); + `checkh(b, 10); + b = cls.get_val_set_2(st.arr[1][2][0].x); + `checkh(st.arr[1][2][0].x, 2); + `checkh(b, 5); + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_std_randomize_with.v b/test_regress/t/t_std_randomize_with.v index 8faa3a9da..1428f763b 100644 --- a/test_regress/t/t_std_randomize_with.v +++ b/test_regress/t/t_std_randomize_with.v @@ -5,49 +5,94 @@ // SPDX-License-Identifier: CC0-1.0 class external_cl; - int x; - int y; + int x; + int y; + logic [7:0] dyn[][]; - function new(); - x = 0; - y = 0; - endfunction + function new(); + x = 0; + y = 0; + dyn = new[4]; + foreach (dyn[i]) dyn[i] = new[1]; + endfunction endclass module t; - initial begin - int a, b; - automatic int limit = 10; - external_cl obj; + initial begin + int a, b; + automatic int limit = 10; + external_cl obj; - // Test 1: Basic std::randomize with 'with' clause - if (std::randomize(a, b) with { 2 < a; a < 7; b < a; } != 1) $stop; - if (!(2 < a && a < 7 && b < a)) $stop; - $display("Test 1 passed: a=%0d, b=%0d", a, b); + // Test 1: Basic std::randomize with 'with' clause + if (std::randomize( + a, b + ) with { + 2 < a; + a < 7; + b < a; + } != 1) + $stop; + if (!(2 < a && a < 7 && b < a)) $stop; + $display("Test 1 passed: a=%0d, b=%0d", a, b); - // Test 2: Local variable and class member with mutual constraints - obj = new; - if (std::randomize(a, obj.x) with { a > 10; a < 20; obj.x > a; obj.x < a + 5; } != 1) $stop; - if (!(a > 10 && a < 20 && obj.x > a && obj.x < a + 5)) $stop; - $display("Test 2 passed: a=%0d, obj.x=%0d (obj.x between a+1 and a+4)", a, obj.x); + // Test 2: Local variable and class member with mutual constraints + obj = new; + if (std::randomize( + a, obj.x + ) with { + a > 10; + a < 20; + obj.x > a; + obj.x < a + 5; + } != 1) + $stop; + if (!(a > 10 && a < 20 && obj.x > a && obj.x < a + 5)) $stop; + $display("Test 2 passed: a=%0d, obj.x=%0d (obj.x between a+1 and a+4)", a, obj.x); - // Test 3: Reference external variable in constraint - if (std::randomize(a) with { a > 0; a < limit; } != 1) $stop; - if (!(a > 0 && a < limit)) $stop; - $display("Test 3 passed: a=%0d, limit=%0d", a, limit); + // Test 3: Reference external variable in constraint + if (std::randomize( + a + ) with { + a > 0; + a < limit; + } != 1) + $stop; + if (!(a > 0 && a < limit)) $stop; + $display("Test 3 passed: a=%0d, limit=%0d", a, limit); - // Test 4: Randomize class member variables - obj = new; - if (std::randomize(obj.x, obj.y) with { obj.x > 5; obj.x < 20; obj.y == obj.x + 1; } != 1) $stop; - if (!(obj.x > 5 && obj.x < 20 && obj.y == obj.x + 1)) $stop; - $display("Test 4 passed: obj.x=%0d, obj.y=%0d", obj.x, obj.y); + // Test 4: Randomize class member variables + obj = new; + if (std::randomize( + obj.x, obj.y + ) with { + obj.x > 5; + obj.x < 20; + obj.y == obj.x + 1; + } != 1) + $stop; + if (!(obj.x > 5 && obj.x < 20 && obj.y == obj.x + 1)) $stop; + $display("Test 4 passed: obj.x=%0d, obj.y=%0d", obj.x, obj.y); - // Test 5: Multiple class members and local variable - if (std::randomize(a, obj.x, obj.y) with { a > 0; a < 5; obj.x > a; obj.y > obj.x; obj.y < a + 10; } != 1) $stop; - if (!(a > 0 && a < 5 && obj.x > a && obj.y > obj.x && obj.y < a + 10)) $stop; - $display("Test 5 passed: a=%0d, obj.x=%0d, obj.y=%0d", a, obj.x, obj.y); + // Test 5: Multiple class members and local variable + if (std::randomize( + a, obj.x, obj.y + ) with { + a > 0; + a < 5; + obj.x > a; + obj.y > obj.x; + obj.y < a + 10; + } != 1) + $stop; + if (!(a > 0 && a < 5 && obj.x > a && obj.y > obj.x && obj.y < a + 10)) $stop; + $display("Test 5 passed: a=%0d, obj.x=%0d, obj.y=%0d", a, obj.x, obj.y); - $write("*-* All Finished *-*\n"); - $finish; - end + // Test 6: Member of 2D array + assert (std::randomize(obj.dyn[2][0]) with {obj.dyn[2][0] inside {[1 : 10]};} == 1); + if (!(obj.dyn[2][0] inside {[1 : 10]})) $stop; + $display("Test 6 passed: obj.dyn[2][0]=%0d", obj.dyn[2][0]); + + $write("*-* All Finished *-*\n"); + $finish; + end endmodule