Skip to content

Commit

Permalink
Support associative array basic constrained randomization (verilator#…
Browse files Browse the repository at this point in the history
  • Loading branch information
YilouWang authored Dec 12, 2024
1 parent 32f9cf0 commit 54ef9ad
Show file tree
Hide file tree
Showing 11 changed files with 438 additions and 98 deletions.
6 changes: 3 additions & 3 deletions include/verilated_random.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -464,10 +464,10 @@ bool VlRandomizer::parseSolution(std::iostream& f) {
const size_t start = hex_index.find_first_not_of(" ");
if (start == std::string::npos || hex_index.substr(start, 2) != "#x") {
VL_FATAL_MT(__FILE__, __LINE__, "randomize",
"Error: hex_index contains invalid format");
"hex_index contains invalid format");
continue;
}
const int index = std::stoi(hex_index.substr(start + 2), nullptr, 16);
const long long index = std::stoll(hex_index.substr(start + 2), nullptr, 16);
oss << "[" << index << "]";
}
const std::string indexed_name = oss.str();
Expand All @@ -481,7 +481,7 @@ bool VlRandomizer::parseSolution(std::iostream& f) {
idx = ss.str();
} else {
VL_FATAL_MT(__FILE__, __LINE__, "randomize",
"Error: indexed_name not found in m_arr_vars");
"indexed_name not found in m_arr_vars");
}
}
varr.set(idx, value);
Expand Down
221 changes: 129 additions & 92 deletions include/verilated_random.h

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/V3AstNodeExpr.h
Original file line number Diff line number Diff line change
Expand Up @@ -4191,6 +4191,7 @@ class AstAssocSel final : public AstNodeSel {
}
string emitVerilog() override { return "%k(%l%f[%r])"; }
string emitC() override { return "%li%k[%ri]"; }
string emitSMT() const override { return "(select %l %r)"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return true; }
Expand Down
42 changes: 40 additions & 2 deletions src/V3Randomize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -641,7 +641,7 @@ class ConstraintExprVisitor final : public VNVisitor {
"write_var"};
uint32_t dimension = 0;
if (VN_IS(varp->dtypep(), UnpackArrayDType) || VN_IS(varp->dtypep(), DynArrayDType)
|| VN_IS(varp->dtypep(), QueueDType)) {
|| VN_IS(varp->dtypep(), QueueDType) || VN_IS(varp->dtypep(), AssocArrayDType)) {
const std::pair<uint32_t, uint32_t> dims
= varp->dtypep()->dimensions(/*includeBasic=*/true);
const uint32_t unpackedDimensions = dims.second;
Expand All @@ -656,7 +656,7 @@ class ConstraintExprVisitor final : public VNVisitor {
size_t width = varp->width();
AstNodeDType* tmpDtypep = varp->dtypep();
while (VN_IS(tmpDtypep, UnpackArrayDType) || VN_IS(tmpDtypep, DynArrayDType)
|| VN_IS(tmpDtypep, QueueDType))
|| VN_IS(tmpDtypep, QueueDType) || VN_IS(tmpDtypep, AssocArrayDType))
tmpDtypep = tmpDtypep->subDTypep();
width = tmpDtypep->width();
methodp->addPinsp(
Expand Down Expand Up @@ -724,6 +724,44 @@ class ConstraintExprVisitor final : public VNVisitor {

editSMT(nodep, nodep->fromp(), lsbp, msbp);
}
void visit(AstAssocSel* nodep) override {
if (editFormat(nodep)) return;
FileLine* const fl = nodep->fileline();
if (VN_IS(nodep->bitp(), CvtPackString)) {
// Extract and truncate the string index to fit within 64 bits
AstCvtPackString* const stringp = VN_AS(nodep->bitp(), CvtPackString);
VNRelinker handle;
AstNodeExpr* const strIdxp = new AstSFormatF{
fl, "#x%16x", false,
new AstAnd{fl, stringp->lhsp()->unlinkFrBack(&handle),
new AstConst(fl, AstConst::Unsized64{}, 0xFFFFFFFFFFFFFFFF)}};
handle.relink(strIdxp);
editSMT(nodep, nodep->fromp(), strIdxp);
} else {
VNRelinker handle;
const int actual_width = nodep->bitp()->width();
std::string fmt;
// Normalize to standard bit width
if (actual_width <= 8) {
fmt = "#x%2x";
} else if (actual_width <= 16) {
fmt = "#x%4x";
} else if (actual_width <= 32) {
fmt = "#x%8x";
} else if (actual_width <= 64) {
fmt = "#x%16x";
} else {
nodep->v3warn(CONSTRAINTIGN,
"Unsupported: Associative array index "
"widths of more than 64 bits during constraint randomization.");
return;
}
AstNodeExpr* const idxp
= new AstSFormatF{fl, fmt, false, nodep->bitp()->unlinkFrBack(&handle)};
handle.relink(idxp);
editSMT(nodep, nodep->fromp(), idxp);
}
}
void visit(AstArraySel* nodep) override {
if (editFormat(nodep)) return;
FileLine* const fl = nodep->fileline();
Expand Down
9 changes: 9 additions & 0 deletions test_regress/t/t_constraint_assoc_arr_bad.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
%Warning-CONSTRAINTIGN: t/t_constraint_assoc_arr_bad.v:14:22: Unsupported: Associative array index widths of more than 64 bits during constraint randomization.
14 | bit_index_arr[79'd66] == 65;
| ^
... For warning description see https://verilator.org/warn/CONSTRAINTIGN?v=latest
... Use "/* verilator lint_off CONSTRAINTIGN */" and lint_on around source to disable this message.
%Warning-CONSTRAINTIGN: t/t_constraint_assoc_arr_bad.v:15:24: Unsupported: Associative array index widths of more than 64 bits during constraint randomization.
15 | logic_index_arr[65'd3] == 70;
| ^
%Error: Exiting due to
16 changes: 16 additions & 0 deletions test_regress/t/t_constraint_assoc_arr_bad.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2024 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0

import vltest_bootstrap

test.scenarios('simulator')

test.lint(fails=True, expect_filename=test.golden_filename)

test.passes()
38 changes: 38 additions & 0 deletions test_regress/t/t_constraint_assoc_arr_bad.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2024 by PlanV GmbH.
// SPDX-License-Identifier: CC0-1.0


class AssocArrayWarningTest;

rand int bit_index_arr [bit[78:0]];
rand int logic_index_arr [logic[64:0]];

constraint c {
bit_index_arr[79'd66] == 65;
logic_index_arr[65'd3] == 70;
}
function new();
bit_index_arr = '{79'd66:0};
logic_index_arr = '{65'd3:0};
endfunction

endclass

module t_constraint_assoc_arr_bad;

AssocArrayWarningTest test_obj;

initial begin
test_obj = new();
repeat(2) begin
int success;
success = test_obj.randomize();
if (success != 1) $stop;
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
180 changes: 180 additions & 0 deletions test_regress/t/t_constraint_assoc_arr_basic.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2024 by PlanV GmbH.
// SPDX-License-Identifier: CC0-1.0

class constrained_associative_array_basic;

rand int int_index_arr [int];
rand int string_index_arr [string];
/* verilator lint_off SIDEEFFECT */
// Constraints for both arrays
constraint int_index_constraints {
foreach (int_index_arr[i]) int_index_arr[i] inside {10, 20, 30, 40, 50};
}
constraint string_index_constraints {
string_index_arr["Alice"] == 35;
string_index_arr["Bob"] inside {50, 60};
string_index_arr["Charlie"] > 25;
}

// Constructor to initialize arrays
function new();
int_index_arr = '{1: 0, 8: 0, 7: 0};
string_index_arr = '{"Alice": 25, "Bob": 50, "Charlie": 45};
endfunction

// Function to check and display the arrays
function void self_check();
foreach (int_index_arr[i]) begin
if (!(int_index_arr[i] inside {10, 20, 30, 40, 50})) $stop;
end
foreach (string_index_arr[name]) begin
if ((name == "Alice" && string_index_arr[name] != 35) ||
(name == "Bob" && !(string_index_arr[name] inside {50, 60})) ||
(name == "Charlie" && string_index_arr[name] <= 25)) $stop;
end
endfunction

endclass

class constrained_1d_associative_array;

rand int string_index_arr [string];
rand int int_index_arr [int];
rand int shortint_index_arr [shortint];
rand int longint_index_arr[longint];
rand int byte_index_arr [byte];
rand int bit_index_arr [bit[5:0]];
rand int logic_index_arr [logic[3:0]];
rand int bit_index_arr_1 [bit[55:0]];

// Constraints
constraint associative_array_constraints {
string_index_arr["key1"] == 100;
string_index_arr["key2"] inside {200, 300, 400};
int_index_arr[40000] + int_index_arr[2000000000] == 2;
shortint_index_arr[2000] == 200;
longint_index_arr[64'd4000000000] == 300;
byte_index_arr[8'd255] == 50;
bit_index_arr[6'd30] - bit_index_arr_1[56'd66] == 3;
logic_index_arr[4'b0011] == 70;
}

function new();
string_index_arr = '{"key1":0, "key2":0};
int_index_arr = '{40000:0, 2000000000:0};
shortint_index_arr = '{2000:0};
longint_index_arr = '{64'd4000000000:0};
byte_index_arr = '{8'd255:0};
bit_index_arr = '{6'd30:0};
bit_index_arr_1 = '{56'd66:0};
logic_index_arr = '{4'd3:0};
endfunction

function void self_check();
if (string_index_arr["key1"] != 100) $stop;
if (!(string_index_arr["key2"] inside {200, 300, 400})) $stop;
if ((int_index_arr[40000] + int_index_arr[2000000000]) != 2) $stop;
if (shortint_index_arr[2000] != 200) $stop;
if (longint_index_arr[64'd4000000000] != 300) $stop;
if (byte_index_arr[8'd255] != 50) $stop;
if (bit_index_arr[6'd30] - bit_index_arr_1[56'd66] != 3) $stop;
if (logic_index_arr[4'd3] != 70) $stop;
endfunction

function void debug_display();
$display("string_index_arr[\"key1\"] = %0d", string_index_arr["key1"]);
$display("string_index_arr[\"key2\"] = %0d", string_index_arr["key2"]);
$display("int_index_arr[40000] = %0d", int_index_arr[40000]);
$display("int_index_arr[2000000000] = %0d", int_index_arr[2000000000]);
$display("shortint_index_arr[2000] = %0d", shortint_index_arr[2000]);
$display("longint_index_arr[4000000000] = %0d", longint_index_arr[64'd4000000000]);
$display("byte_index_arr[255] = %0d", byte_index_arr[8'd255]);
$display("bit_index_arr[30] = %0d", bit_index_arr[6'd30]);
$display("bit_index_arr_1[66] = %0d", bit_index_arr_1[56'd66]);
$display("logic_index_arr[3] = %0d", logic_index_arr[4'd3]);
endfunction

endclass

class constrained_2d_associative_array;

rand int string_int_index_arr [string][int];
rand int int_bit_index_arr [int][bit[5:0]];
rand int string_bit_index_arr [string][bit[7:0]];
rand int unpacked_assoc_array_2d [string][2];

// Constraints
constraint associative_array_constraints {
string_int_index_arr["key1"][2000] == 100;
string_int_index_arr["key2"][3000] inside {200, 300, 400};
int_bit_index_arr[40000][6'd30] == 60;
int_bit_index_arr[50000][6'd40] inside {100, 200};
string_bit_index_arr["key3"][8'd100] == 150;
string_bit_index_arr["key4"][8'd200] inside {250, 350};
unpacked_assoc_array_2d["key5"][0] == 7;
}

function new();
string_int_index_arr = '{"key1":'{2000:0}, "key2":'{3000:0}};
int_bit_index_arr = '{40000:'{6'd30:0}, 50000:'{6'd40:0}};
string_bit_index_arr = '{"key3":'{8'd100:0}, "key4":'{8'd200:0}};
unpacked_assoc_array_2d["key5"][0] = 0;
unpacked_assoc_array_2d["key5"][1] = 0;
endfunction

function void self_check();
if (string_int_index_arr["key1"][2000] != 100) $stop;
if (!(string_int_index_arr["key2"][3000] inside {200, 300, 400})) $stop;
if (int_bit_index_arr[40000][6'd30] != 60) $stop;
if (!(int_bit_index_arr[50000][6'd40] inside {100, 200})) $stop;
if (string_bit_index_arr["key3"][8'd100] != 150) $stop;
if (!(string_bit_index_arr["key4"][8'd200] inside {250, 350})) $stop;
if (unpacked_assoc_array_2d["key5"][0] != 7) $stop;
endfunction

function void debug_display();
$display("string_int_index_arr[\"key1\"][2000] = %0d", string_int_index_arr["key1"][2000]);
$display("string_int_index_arr[\"key2\"][3000] = %0d", string_int_index_arr["key2"][3000]);
$display("int_bit_index_arr[40000][30] = %0d", int_bit_index_arr[40000][6'd30]);
$display("int_bit_index_arr[50000][40] = %0d", int_bit_index_arr[50000][6'd40]);
$display("string_bit_index_arr[\"key3\"][100] = %0d", string_bit_index_arr["key3"][8'd100]);
$display("string_bit_index_arr[\"key4\"][200] = %0d", string_bit_index_arr["key4"][8'd200]);
$display("unpacked_assoc_array_2d[\"key5\"][0] = %0d", unpacked_assoc_array_2d["key5"][0]);
endfunction
/* verilator lint_off SIDEEFFECT */
endclass

module t_constraint_assoc_arr_basic;

constrained_associative_array_basic my_array;
constrained_1d_associative_array my_1d_array;
constrained_2d_associative_array my_2d_array;
int success;

initial begin
my_array = new();
success = my_array.randomize();
if (success == 0) $stop;
my_array.self_check();

my_1d_array = new();
success = my_1d_array.randomize();
if (success == 0) $stop;
my_1d_array.self_check();

my_1d_array = new();
success = my_1d_array.randomize();
if (success == 0) $stop;
my_1d_array.self_check();

// my_1d_array.debug_display();
// my_2d_array.debug_display();

$write("*-* All Finished *-*\n");
$finish;
end

endmodule
21 changes: 21 additions & 0 deletions test_regress/t/t_constraint_unpacked_array.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2024 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0

import vltest_bootstrap

test.scenarios('simulator')

if not test.have_solver:
test.skip("No constraint solver installed")

test.compile()

test.execute()

test.passes()
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ class con_rand_3d_array_test;
endclass


module t_randomize_array_constraints;
module t_constraint_unpacked_array;
con_rand_1d_array_test rand_test_1;
con_rand_2d_array_test rand_test_2;
con_rand_3d_array_test rand_test_3;
Expand Down

0 comments on commit 54ef9ad

Please sign in to comment.