mirror of
https://github.com/verilator/verilator.git
synced 2024-12-29 10:47:34 +00:00
This commit is contained in:
parent
9bde98e912
commit
5470cf9fa9
@ -570,6 +570,7 @@ public:
|
||||
m_deque.resize(size, atDefault());
|
||||
}
|
||||
}
|
||||
void resize(size_t size) { m_deque.resize(size, atDefault()); }
|
||||
|
||||
// function void q.push_front(value)
|
||||
void push_front(const T_Value& value) {
|
||||
|
@ -2903,6 +2903,7 @@ void AstCMethodHard::setPurity() {
|
||||
{"r_xor", true},
|
||||
{"renew", false},
|
||||
{"renew_copy", false},
|
||||
{"resize", false},
|
||||
{"resume", false},
|
||||
{"reverse", false},
|
||||
{"rsort", false},
|
||||
|
@ -606,6 +606,12 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||
// VISITORS
|
||||
void visit(AstNodeVarRef* nodep) override {
|
||||
AstVar* const varp = nodep->varp();
|
||||
if (varp->user4p()) {
|
||||
varp->user4p()->v3warn(
|
||||
CONSTRAINTIGN,
|
||||
"Size constraint combined with element constraint may not work correctly");
|
||||
}
|
||||
|
||||
AstNodeModule* const classOrPackagep = nodep->classOrPackagep();
|
||||
const RandomizeMode randMode = {.asInt = varp->user1()};
|
||||
if (!randMode.usesMode && editFormat(nodep)) return;
|
||||
@ -1132,7 +1138,9 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
// AstClass::user2p() -> AstVar*. Rand mode state variable
|
||||
// AstVar::user3() -> bool. Handled in constraints
|
||||
// AstClass::user3p() -> AstVar*. Constrained randomizer variable
|
||||
// AstConstraint::user3p() -> AstTask*. Pointer to resize procedure
|
||||
// AstClass::user4p() -> AstVar*. Constraint mode state variable
|
||||
// AstVar::user4p() -> AstVar*. Size variable for constrained queues
|
||||
// VNUser1InUse m_inuser1; (Allocated for use in RandomizeMarkVisitor)
|
||||
// VNUser2InUse m_inuser2; (Allocated for use in RandomizeMarkVisitor)
|
||||
const VNUser3InUse m_inuser3;
|
||||
@ -1150,6 +1158,7 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
size_t m_enumValueTabCount = 0; // Number of tables with enum values created
|
||||
int m_randCaseNum = 0; // Randcase number within a module for var naming
|
||||
std::map<std::string, AstCDType*> m_randcDtypes; // RandC data type deduplication
|
||||
AstConstraint* m_constraintp = nullptr; // Current constraint
|
||||
|
||||
// METHODS
|
||||
void createRandomGenerator(AstClass* const classp) {
|
||||
@ -1180,6 +1189,17 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
m_memberMap.insert(classp, setupAllTaskp);
|
||||
return setupAllTaskp;
|
||||
}
|
||||
AstTask* getCreateAggrResizeTask(AstClass* const classp) {
|
||||
static const char* const name = "__Vresize_constrained_arrays";
|
||||
AstTask* resizeTaskp = VN_AS(m_memberMap.findMember(classp, name), Task);
|
||||
if (resizeTaskp) return resizeTaskp;
|
||||
resizeTaskp = new AstTask{classp->fileline(), name, nullptr};
|
||||
resizeTaskp->classMethod(true);
|
||||
resizeTaskp->isVirtual(true);
|
||||
classp->addMembersp(resizeTaskp);
|
||||
m_memberMap.insert(classp, resizeTaskp);
|
||||
return resizeTaskp;
|
||||
}
|
||||
AstVar* getCreateRandModeVar(AstClass* const classp) {
|
||||
if (classp->user2p()) return VN_AS(classp->user2p(), Var);
|
||||
if (AstClassExtends* const extendsp = classp->extendsp()) {
|
||||
@ -1281,8 +1301,7 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
FileLine* fl = modeVarp->fileline();
|
||||
AstCMethodHard* const dynarrayNewp
|
||||
= new AstCMethodHard{fl, new AstVarRef{fl, modeVarModp, modeVarp, VAccess::WRITE},
|
||||
"renew_copy", new AstConst{fl, modeCount}};
|
||||
dynarrayNewp->addPinsp(new AstVarRef{fl, modeVarModp, modeVarp, VAccess::READ});
|
||||
"resize", new AstConst{fl, modeCount}};
|
||||
dynarrayNewp->dtypeSetVoid();
|
||||
AstNodeFTask* const newp = VN_AS(m_memberMap.findMember(classp, "new"), NodeFTask);
|
||||
UASSERT_OBJ(newp, classp, "No new() in class");
|
||||
@ -1565,6 +1584,13 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
nodep->addMembersp(taskp);
|
||||
return taskp;
|
||||
}
|
||||
AstTask* newResizeConstrainedArrayTask(AstClass* const nodep, const std::string& name) {
|
||||
AstTask* const taskp
|
||||
= new AstTask{nodep->fileline(), name + "_resize_constrained_array", nullptr};
|
||||
taskp->classMethod(true);
|
||||
nodep->addMembersp(taskp);
|
||||
return taskp;
|
||||
}
|
||||
AstNodeStmt* implementConstraintsClear(FileLine* const fileline, AstVar* const genp) {
|
||||
AstCMethodHard* const clearp = new AstCMethodHard{
|
||||
fileline,
|
||||
@ -1898,6 +1924,15 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
|
||||
setupAllTaskp->addStmtsp(setupTaskRefp->makeStmt());
|
||||
|
||||
if (AstTask* const resizeTaskp = VN_CAST(constrp->user3p(), Task)) {
|
||||
AstTask* const resizeAllTaskp = getCreateAggrResizeTask(nodep);
|
||||
AstTaskRef* const resizeTaskRefp
|
||||
= new AstTaskRef{constrp->fileline(), resizeTaskp->name(), nullptr};
|
||||
resizeTaskRefp->taskp(resizeTaskp);
|
||||
resizeTaskRefp->classOrPackagep(classp);
|
||||
resizeAllTaskp->addStmtsp(resizeTaskRefp->makeStmt());
|
||||
}
|
||||
|
||||
ConstraintExprVisitor{m_memberMap, constrp->itemsp(), nullptr, genp, randModeVarp};
|
||||
if (constrp->itemsp()) {
|
||||
taskp->addStmtsp(wrapIfConstraintMode(
|
||||
@ -1933,6 +1968,13 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
AstVarRef* const fvarRefp = new AstVarRef{fl, fvarp, VAccess::WRITE};
|
||||
randomizep->addStmtsp(new AstAssign{fl, fvarRefp, beginValp});
|
||||
|
||||
if (AstTask* const resizeAllTaskp
|
||||
= VN_AS(m_memberMap.findMember(nodep, "__Vresize_constrained_arrays"), Task)) {
|
||||
AstTaskRef* const resizeTaskRefp = new AstTaskRef{fl, resizeAllTaskp->name(), nullptr};
|
||||
resizeTaskRefp->taskp(resizeAllTaskp);
|
||||
randomizep->addStmtsp(resizeTaskRefp->makeStmt());
|
||||
}
|
||||
|
||||
AstFunc* const basicRandomizep
|
||||
= V3Randomize::newRandomizeFunc(m_memberMap, nodep, "__Vbasic_randomize");
|
||||
addBasicRandomizeBody(basicRandomizep, nodep, randModeVarp);
|
||||
@ -2161,6 +2203,57 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
UINFO(9, "Added `%s` randomization procedure");
|
||||
VL_DO_DANGLING(withp->deleteTree(), withp);
|
||||
}
|
||||
void visit(AstConstraint* nodep) override {
|
||||
VL_RESTORER(m_constraintp);
|
||||
m_constraintp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstCMethodHard* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
FileLine* const fl = nodep->fileline();
|
||||
if (m_constraintp && nodep->fromp()->user1() && nodep->name() == "size") {
|
||||
AstClass* const classp = VN_AS(m_modp, Class);
|
||||
AstVarRef* const queueVarRefp = VN_CAST(nodep->fromp(), VarRef);
|
||||
if (!queueVarRefp) {
|
||||
// Warning from ConstraintExprVisitor will be thrown
|
||||
return;
|
||||
}
|
||||
AstVar* const queueVarp = queueVarRefp->varp();
|
||||
AstVar* sizeVarp = VN_CAST(queueVarp->user4p(), Var);
|
||||
if (!sizeVarp) {
|
||||
sizeVarp = new AstVar{fl, VVarType::BLOCKTEMP, "__V" + queueVarp->name() + "_size",
|
||||
nodep->findSigned32DType()};
|
||||
classp->addMembersp(sizeVarp);
|
||||
m_memberMap.insert(classp, sizeVarp);
|
||||
sizeVarp->user2p(classp);
|
||||
|
||||
queueVarp->user4p(sizeVarp);
|
||||
|
||||
AstTask* resizerTaskp = VN_AS(m_constraintp->user3p(), Task);
|
||||
if (!resizerTaskp) {
|
||||
resizerTaskp = newResizeConstrainedArrayTask(classp, m_constraintp->name());
|
||||
m_constraintp->user3p(resizerTaskp);
|
||||
}
|
||||
AstCMethodHard* const resizep
|
||||
= new AstCMethodHard{fl, nodep->fromp()->unlinkFrBack(), "resize",
|
||||
new AstVarRef{fl, sizeVarp, VAccess::READ}};
|
||||
resizep->dtypep(nodep->findVoidDType());
|
||||
resizerTaskp->addStmtsp(new AstStmtExpr{fl, resizep});
|
||||
|
||||
// Since size variable is signed int, we need additional constraint
|
||||
// to make sure it is always >= 0.
|
||||
AstVarRef* const sizeVarRefp = new AstVarRef{fl, sizeVarp, VAccess::READ};
|
||||
sizeVarRefp->user1(true);
|
||||
AstGteS* const sizeGtep = new AstGteS{fl, sizeVarRefp, new AstConst{fl, 0}};
|
||||
sizeGtep->user1(true);
|
||||
m_constraintp->addItemsp(new AstConstraintExpr{fl, sizeGtep});
|
||||
}
|
||||
AstVarRef* const sizeVarRefp = new AstVarRef{fl, sizeVarp, VAccess::READ};
|
||||
sizeVarRefp->user1(true);
|
||||
nodep->replaceWith(sizeVarRefp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
void visit(AstNodeStmt* nodep) override {
|
||||
VL_RESTORER(m_stmtp);
|
||||
m_stmtp = nodep;
|
||||
|
@ -1,10 +1,17 @@
|
||||
%Warning-CONSTRAINTIGN: t/t_randomize_method_types_unsup.v:13:32: Unsupported: randomizing this expression, treating as state
|
||||
13 | constraint dynsize { dynarr.size < 20; }
|
||||
| ^~~~
|
||||
%Warning-CONSTRAINTIGN: t/t_randomize_method_types_unsup.v:17:17: Unsupported: randomizing this expression, treating as state
|
||||
17 | dynarr[1].size < 10;
|
||||
| ^~~~
|
||||
... 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.
|
||||
%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:10:13: Unsupported: random member variable with the type of the containing class
|
||||
%Warning-CONSTRAINTIGN: t/t_randomize_method_types_unsup.v:21:9: Size constraint combined with element constraint may not work correctly
|
||||
: ... note: In instance 't'
|
||||
21 | q.size < 5;
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:11:13: Unsupported: random member variable with the type of the containing class
|
||||
: ... note: In instance 't'
|
||||
10 | rand Cls cls;
|
||||
11 | rand Cls cls;
|
||||
| ^~~
|
||||
%Warning-CONSTRAINTIGN: t/t_randomize_method_types_unsup.v:33:43: Unsupported: randomizing this expression, treating as state
|
||||
33 | res = obj.randomize() with { dynarr.size > 2; };
|
||||
| ^~~~
|
||||
%Error: Exiting due to
|
||||
|
@ -6,12 +6,21 @@
|
||||
|
||||
class Cls;
|
||||
rand int assocarr[string];
|
||||
rand int dynarr[];
|
||||
rand int dynarr[][];
|
||||
rand int q[$];
|
||||
rand Cls cls;
|
||||
rand int i;
|
||||
int st;
|
||||
constraint dynsize { dynarr.size < 20; }
|
||||
constraint dynsize {
|
||||
dynarr.size < 20;
|
||||
dynarr.size > 0;
|
||||
dynarr[1].size < 10;
|
||||
}
|
||||
constraint statedep { i < st + 2; }
|
||||
constraint q_size_elem {
|
||||
q.size < 5;
|
||||
q[i] < 10;
|
||||
}
|
||||
endclass
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
@ -21,5 +30,6 @@ module t (/*AUTOARG*/);
|
||||
initial begin
|
||||
obj = new;
|
||||
res = obj.randomize();
|
||||
res = obj.randomize() with { dynarr.size > 2; };
|
||||
end
|
||||
endmodule
|
||||
|
21
test_regress/t/t_randomize_queue_size.py
Executable file
21
test_regress/t/t_randomize_queue_size.py
Executable file
@ -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()
|
85
test_regress/t/t_randomize_queue_size.v
Executable file
85
test_regress/t/t_randomize_queue_size.v
Executable file
@ -0,0 +1,85 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2024 by Antmicro Ltd.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
`define check_rand(cl, field, cond) \
|
||||
begin \
|
||||
longint prev_result; \
|
||||
int ok = 0; \
|
||||
if (!bit'(cl.randomize())) $stop; \
|
||||
prev_result = longint'(field); \
|
||||
if (!(cond)) $stop; \
|
||||
repeat(9) begin \
|
||||
longint result; \
|
||||
if (!bit'(cl.randomize())) $stop; \
|
||||
result = longint'(field); \
|
||||
if (!(cond)) $stop; \
|
||||
if (result != prev_result) ok = 1; \
|
||||
prev_result = result; \
|
||||
end \
|
||||
if (ok != 1) $stop; \
|
||||
end
|
||||
|
||||
class Foo;
|
||||
rand int q[$];
|
||||
rand int q2[$][$];
|
||||
int x = 1;
|
||||
constraint c {
|
||||
q.size() == 15;
|
||||
q2.size() == 10;
|
||||
}
|
||||
endclass
|
||||
|
||||
class Bar;
|
||||
rand int q[$];
|
||||
rand int min_size;
|
||||
rand int q2[$];
|
||||
constraint c {
|
||||
min_size > 2;
|
||||
q.size() >= min_size;
|
||||
q.size() < 10;
|
||||
};
|
||||
constraint c2 {
|
||||
q2.size() < 7;
|
||||
}
|
||||
endclass
|
||||
|
||||
class Baz;
|
||||
rand Foo foo_arr[];
|
||||
constraint c_foo {
|
||||
foo_arr.size == 7;
|
||||
}
|
||||
endclass
|
||||
|
||||
module t;
|
||||
initial begin
|
||||
Foo foo = new;
|
||||
Bar bar = new;
|
||||
Baz baz = new;
|
||||
|
||||
void'(foo.randomize());
|
||||
if (foo.q.size() != 15) $stop;
|
||||
if (foo.q2.size() != 10) $stop;
|
||||
|
||||
`check_rand(bar, bar.q.size(), bar.q.size() > 2 && bar.q.size() < 10);
|
||||
`check_rand(bar, bar.q2.size(), bar.q2.size() < 7);
|
||||
|
||||
baz.foo_arr = new[4];
|
||||
for (int i = 0; i < 4; i++) baz.foo_arr[i] = new;
|
||||
baz.foo_arr[2].x = 2;
|
||||
void'(baz.randomize());
|
||||
|
||||
if (baz.foo_arr.size() != 7) $stop;
|
||||
for (int i = 0; i < 4; i++)
|
||||
if (baz.foo_arr[i] == null) $stop;
|
||||
for (int i = 4; i < 7; i++)
|
||||
if (baz.foo_arr[i] != null) $stop;
|
||||
if (baz.foo_arr[2].x != 2) $stop;
|
||||
`check_rand(baz, baz.foo_arr[1].q[5], 1'b1);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
@ -22444,9 +22444,7 @@ class uvm_reg_item extends uvm_sequence_item;
|
||||
uvm_elem_kind_e element_kind;
|
||||
uvm_object element;
|
||||
rand uvm_access_e kind;
|
||||
//TODO issue-5582 - Rand constraint with .size
|
||||
//TODO %Warning-CONSTRAINTIGN: t/t_uvm_pkg_todo.vh:#:#: Unsupported: randomizing this expression, treating as state
|
||||
/*rand*/ uvm_reg_data_t value[];
|
||||
rand uvm_reg_data_t value[];
|
||||
constraint max_values { value.size() > 0 && value.size() < 1000; }
|
||||
rand uvm_reg_addr_t offset;
|
||||
uvm_status_e status;
|
||||
@ -26866,9 +26864,7 @@ class uvm_reg_fifo extends uvm_reg;
|
||||
local uvm_reg_field value;
|
||||
local int m_set_cnt;
|
||||
local int unsigned m_size;
|
||||
//TODO issue-5582 - Rand constraint with .size
|
||||
//TODO %Warning-CONSTRAINTIGN: t/t_uvm_pkg_todo.vh:#:#: Unsupported: randomizing this expression, treating as state
|
||||
/*rand*/ uvm_reg_data_t fifo[$];
|
||||
rand uvm_reg_data_t fifo[$];
|
||||
constraint valid_fifo_size {
|
||||
fifo.size() <= m_size;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user