This commit is contained in:
parent
7fc428f518
commit
994ef82e76
|
|
@ -604,6 +604,14 @@ class RandomizeMarkVisitor final : public VNVisitor {
|
||||||
handleRandomizeArgument(argp->exprp(), fromVarp, false);
|
handleRandomizeArgument(argp->exprp(), fromVarp, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void visit(AstConstraintUnique* nodep) override {
|
||||||
|
VL_RESTORER(m_stmtp);
|
||||||
|
VL_RESTORER(m_constraintExprGenp);
|
||||||
|
m_stmtp = nodep;
|
||||||
|
m_constraintExprGenp = nodep;
|
||||||
|
iterateChildren(nodep);
|
||||||
|
if (!nodep->backp()) VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||||
|
}
|
||||||
void visit(AstConstraintExpr* nodep) override {
|
void visit(AstConstraintExpr* nodep) override {
|
||||||
VL_RESTORER(m_constraintExprGenp);
|
VL_RESTORER(m_constraintExprGenp);
|
||||||
m_constraintExprGenp = nodep;
|
m_constraintExprGenp = nodep;
|
||||||
|
|
@ -2218,6 +2226,50 @@ class RandomizeVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// Expand unique{a,b,c} with explicit elements into pairwise != constraints.
|
||||||
|
// Whole-array unique{arr} is left for ConstraintExprVisitor's rand_unique handling.
|
||||||
|
static void expandUniqueElementList(AstNode* itemsp) {
|
||||||
|
AstNode* itemp = itemsp;
|
||||||
|
while (itemp) {
|
||||||
|
AstNode* const nextp = itemp->nextp();
|
||||||
|
AstConstraintUnique* const uniquep = VN_CAST(itemp, ConstraintUnique);
|
||||||
|
if (!uniquep) {
|
||||||
|
itemp = nextp;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<AstNodeExpr*> exprItems;
|
||||||
|
bool hasArrayVarRef = false;
|
||||||
|
for (AstNode* rp = uniquep->rangesp(); rp; rp = rp->nextp()) {
|
||||||
|
if (AstVarRef* const vrp = VN_CAST(rp, VarRef)) {
|
||||||
|
if (VN_IS(vrp->varp()->dtypep()->skipRefp(), UnpackArrayDType)) {
|
||||||
|
hasArrayVarRef = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exprItems.push_back(VN_AS(rp, NodeExpr));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exprItems.size() >= 2) {
|
||||||
|
FileLine* const fl = uniquep->fileline();
|
||||||
|
for (size_t i = 0; i < exprItems.size(); i++) {
|
||||||
|
for (size_t j = i + 1; j < exprItems.size(); j++) {
|
||||||
|
AstNodeExpr* const lhsp = exprItems[i]->cloneTree(false);
|
||||||
|
AstNodeExpr* const rhsp = exprItems[j]->cloneTree(false);
|
||||||
|
AstNeq* const neqp = new AstNeq{fl, lhsp, rhsp};
|
||||||
|
neqp->user1(true);
|
||||||
|
AstConstraintExpr* const cexprp = new AstConstraintExpr{fl, neqp};
|
||||||
|
uniquep->addNextHere(cexprp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!hasArrayVarRef) {
|
||||||
|
uniquep->unlinkFrBack();
|
||||||
|
VL_DO_DANGLING(uniquep->deleteTree(), uniquep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
itemp = nextp;
|
||||||
|
}
|
||||||
|
}
|
||||||
void createRandomGenerator(AstClass* const classp) {
|
void createRandomGenerator(AstClass* const classp) {
|
||||||
if (classp->user3p()) return;
|
if (classp->user3p()) return;
|
||||||
if (classp->extendsp()) {
|
if (classp->extendsp()) {
|
||||||
|
|
@ -3232,6 +3284,7 @@ class RandomizeVisitor final : public VNVisitor {
|
||||||
resizeAllTaskp->addStmtsp(resizeTaskRefp->makeStmt());
|
resizeAllTaskp->addStmtsp(resizeTaskRefp->makeStmt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (constrp->itemsp()) expandUniqueElementList(constrp->itemsp());
|
||||||
ConstraintExprVisitor{classp, m_memberMap, constrp->itemsp(), nullptr,
|
ConstraintExprVisitor{classp, m_memberMap, constrp->itemsp(), nullptr,
|
||||||
genp, randModeVarp, m_writtenVars};
|
genp, randModeVarp, m_writtenVars};
|
||||||
if (constrp->itemsp()) {
|
if (constrp->itemsp()) {
|
||||||
|
|
@ -3503,6 +3556,7 @@ class RandomizeVisitor final : public VNVisitor {
|
||||||
AstNode* const capturedTreep = withp->exprp()->unlinkFrBackWithNext();
|
AstNode* const capturedTreep = withp->exprp()->unlinkFrBackWithNext();
|
||||||
randomizeFuncp->addStmtsp(capturedTreep);
|
randomizeFuncp->addStmtsp(capturedTreep);
|
||||||
{
|
{
|
||||||
|
expandUniqueElementList(capturedTreep);
|
||||||
ConstraintExprVisitor{nullptr, m_memberMap, capturedTreep, randomizeFuncp,
|
ConstraintExprVisitor{nullptr, m_memberMap, capturedTreep, randomizeFuncp,
|
||||||
stdrand, nullptr, m_writtenVars};
|
stdrand, nullptr, m_writtenVars};
|
||||||
}
|
}
|
||||||
|
|
@ -3642,6 +3696,7 @@ class RandomizeVisitor final : public VNVisitor {
|
||||||
AstNode* const capturedTreep = withp->exprp()->unlinkFrBackWithNext();
|
AstNode* const capturedTreep = withp->exprp()->unlinkFrBackWithNext();
|
||||||
randomizeFuncp->addStmtsp(capturedTreep);
|
randomizeFuncp->addStmtsp(capturedTreep);
|
||||||
{
|
{
|
||||||
|
expandUniqueElementList(capturedTreep);
|
||||||
ConstraintExprVisitor{classp, m_memberMap, capturedTreep, randomizeFuncp,
|
ConstraintExprVisitor{classp, m_memberMap, capturedTreep, randomizeFuncp,
|
||||||
localGenp, randModeVarp, m_writtenVars};
|
localGenp, randModeVarp, m_writtenVars};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||||
|
# 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()
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||||
|
// SPDX-FileCopyrightText: 2026 PlanV GmbH
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
// verilog_format: off
|
||||||
|
`define stop $stop
|
||||||
|
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||||
|
// verilog_format: on
|
||||||
|
|
||||||
|
// Test unique constraint on explicit array element subsets (IEEE 18.5.9).
|
||||||
|
// bit [3:0] keeps the value space small so collisions are near-certain
|
||||||
|
// without proper constraint enforcement.
|
||||||
|
|
||||||
|
class UniqueElemSubset;
|
||||||
|
rand bit [3:0] arr[10];
|
||||||
|
|
||||||
|
constraint unique_subset_con {
|
||||||
|
unique { arr[2], arr[3], arr[4], arr[5], arr[6] };
|
||||||
|
}
|
||||||
|
|
||||||
|
function new();
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function bit check_unique();
|
||||||
|
for (int i = 2; i <= 6; i++)
|
||||||
|
for (int j = i + 1; j <= 6; j++)
|
||||||
|
if (arr[i] == arr[j]) return 0;
|
||||||
|
return 1;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class UniqueElemFour;
|
||||||
|
rand bit [3:0] data[8];
|
||||||
|
|
||||||
|
constraint unique_data_con {
|
||||||
|
unique { data[1], data[2], data[3], data[4] };
|
||||||
|
}
|
||||||
|
|
||||||
|
function new();
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function bit check_unique();
|
||||||
|
for (int i = 1; i <= 4; i++)
|
||||||
|
for (int j = i + 1; j <= 4; j++)
|
||||||
|
if (data[i] == data[j]) return 0;
|
||||||
|
return 1;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class UniqueElemSingle;
|
||||||
|
rand bit [3:0] val[4];
|
||||||
|
|
||||||
|
constraint unique_single_con {
|
||||||
|
unique { val[0] };
|
||||||
|
}
|
||||||
|
|
||||||
|
function new();
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
module t;
|
||||||
|
UniqueElemSubset ues;
|
||||||
|
UniqueElemFour uef;
|
||||||
|
UniqueElemSingle uesgl;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
ues = new();
|
||||||
|
repeat (20) begin
|
||||||
|
`checkd(ues.randomize(), 1)
|
||||||
|
`checkd(ues.check_unique(), 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
uef = new();
|
||||||
|
repeat (20) begin
|
||||||
|
`checkd(uef.randomize(), 1)
|
||||||
|
`checkd(uef.check_unique(), 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
uesgl = new();
|
||||||
|
repeat (5) begin
|
||||||
|
`checkd(uesgl.randomize(), 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue