Support randcase.
This commit is contained in:
parent
41d2ebe288
commit
a427860825
1
Changes
1
Changes
|
|
@ -15,6 +15,7 @@ Verilator 5.003 devel
|
||||||
|
|
||||||
* Deprecate --no-threads; use --threads 1 for single threaded (#3703). [Kamil Rakoczy, Antmicro Ltd]
|
* Deprecate --no-threads; use --threads 1 for single threaded (#3703). [Kamil Rakoczy, Antmicro Ltd]
|
||||||
* Support named properties (#3667). [Ryszard Rozak, Antmicro Ltd]
|
* Support named properties (#3667). [Ryszard Rozak, Antmicro Ltd]
|
||||||
|
* Support randcase.
|
||||||
* Internal AST improvements, also affect XML format (#3721). [Geza Lore]
|
* Internal AST improvements, also affect XML format (#3721). [Geza Lore]
|
||||||
* Fix return type of $countbits functions to int (#3725). [Ryszard Rozak, Antmicro Ltd]
|
* Fix return type of $countbits functions to int (#3725). [Ryszard Rozak, Antmicro Ltd]
|
||||||
* Fix missing UNUSED warnings with --coverage (#3736). [alejandro-castro-ortegon]
|
* Fix missing UNUSED warnings with --coverage (#3736). [alejandro-castro-ortegon]
|
||||||
|
|
|
||||||
|
|
@ -2839,7 +2839,7 @@ public:
|
||||||
class AstURandomRange final : public AstNodeBiop {
|
class AstURandomRange final : public AstNodeBiop {
|
||||||
// $urandom_range
|
// $urandom_range
|
||||||
public:
|
public:
|
||||||
explicit AstURandomRange(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
AstURandomRange(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
||||||
: ASTGEN_SUPER_URandomRange(fl, lhsp, rhsp) {
|
: ASTGEN_SUPER_URandomRange(fl, lhsp, rhsp) {
|
||||||
dtypeSetUInt32(); // Says IEEE
|
dtypeSetUInt32(); // Says IEEE
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3012,6 +3012,16 @@ public:
|
||||||
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
|
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
|
||||||
VTimescale timeunit() const { return m_timeunit; }
|
VTimescale timeunit() const { return m_timeunit; }
|
||||||
};
|
};
|
||||||
|
class AstRandCase final : public AstNodeStmt {
|
||||||
|
// @astgen op2 := itemsp : List[AstCaseItem]
|
||||||
|
public:
|
||||||
|
AstRandCase(FileLine* fl, AstCaseItem* itemsp)
|
||||||
|
: ASTGEN_SUPER_RandCase(fl) {
|
||||||
|
addItemsp(itemsp);
|
||||||
|
}
|
||||||
|
ASTGEN_MEMBERS_AstRandCase;
|
||||||
|
int instrCount() const override { return INSTR_COUNT_BRANCH; }
|
||||||
|
};
|
||||||
class AstRelease final : public AstNodeStmt {
|
class AstRelease final : public AstNodeStmt {
|
||||||
// Procedural 'release' statement
|
// Procedural 'release' statement
|
||||||
// @astgen op1 := lhsp : AstNode
|
// @astgen op1 := lhsp : AstNode
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,7 @@ private:
|
||||||
markMembers(classp);
|
markMembers(classp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -124,7 +125,9 @@ private:
|
||||||
const VNUser2InUse m_inuser2;
|
const VNUser2InUse m_inuser2;
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
|
AstNodeModule* m_modp = nullptr; // Current module
|
||||||
size_t m_enumValueTabCount = 0; // Number of tables with enum values created
|
size_t m_enumValueTabCount = 0; // Number of tables with enum values created
|
||||||
|
int m_randCaseNum = 0; // Randcase number within a module for var naming
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
AstVar* enumValueTabp(AstEnumDType* nodep) {
|
AstVar* enumValueTabp(AstEnumDType* nodep) {
|
||||||
|
|
@ -197,7 +200,16 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
|
void visit(AstNodeModule* nodep) override {
|
||||||
|
VL_RESTORER(m_randCaseNum);
|
||||||
|
m_modp = nodep;
|
||||||
|
m_randCaseNum = 0;
|
||||||
|
iterateChildren(nodep);
|
||||||
|
}
|
||||||
void visit(AstClass* nodep) override {
|
void visit(AstClass* nodep) override {
|
||||||
|
VL_RESTORER(m_randCaseNum);
|
||||||
|
m_modp = nodep;
|
||||||
|
m_randCaseNum = 0;
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
if (!nodep->user1()) return; // Doesn't need randomize, or already processed
|
if (!nodep->user1()) return; // Doesn't need randomize, or already processed
|
||||||
UINFO(9, "Define randomize() for " << nodep << endl);
|
UINFO(9, "Define randomize() for " << nodep << endl);
|
||||||
|
|
@ -239,6 +251,63 @@ private:
|
||||||
}
|
}
|
||||||
nodep->user1(false);
|
nodep->user1(false);
|
||||||
}
|
}
|
||||||
|
void visit(AstRandCase* nodep) override {
|
||||||
|
// RANDCASE
|
||||||
|
// CASEITEM expr1 : stmt1
|
||||||
|
// CASEITEM expr2 : stmt2
|
||||||
|
// ->
|
||||||
|
// tmp = URandomRange{0, num} + 1 // + 1 so weight 0 means never
|
||||||
|
// if (tmp < expr1) stmt1;
|
||||||
|
// else if (tmp < (expr2 + expr1)) stmt1;
|
||||||
|
// else warning
|
||||||
|
// Note this code assumes that the expressions after V3Const are fast to compute
|
||||||
|
// Optimize: we would be better with a binary search tree to reduce ifs that execute
|
||||||
|
if (debug() >= 9) nodep->dumpTree(cout, "-rcin: ");
|
||||||
|
AstNodeDType* const sumDTypep = nodep->findUInt64DType();
|
||||||
|
|
||||||
|
FileLine* const fl = nodep->fileline();
|
||||||
|
const std::string name = "__Vrandcase" + cvtToStr(m_randCaseNum++);
|
||||||
|
AstVar* const randVarp = new AstVar{fl, VVarType::STMTTEMP, name, sumDTypep};
|
||||||
|
randVarp->noSubst(true);
|
||||||
|
AstNodeExpr* sump = new AstConst{fl, AstConst::WidthedValue{}, 64, 0};
|
||||||
|
AstNodeIf* firstIfsp
|
||||||
|
= new AstIf{fl, new AstConst{fl, AstConst::BitFalse{}}, nullptr, nullptr};
|
||||||
|
AstNodeIf* ifsp = firstIfsp;
|
||||||
|
|
||||||
|
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||||
|
itemp = VN_AS(itemp->nextp(), CaseItem)) {
|
||||||
|
AstNode* const condp = itemp->condsp()->unlinkFrBack();
|
||||||
|
sump
|
||||||
|
= new AstAdd{condp->fileline(), sump, new AstExtend{itemp->fileline(), condp, 64}};
|
||||||
|
AstNode* const stmtsp
|
||||||
|
= itemp->stmtsp() ? itemp->stmtsp()->unlinkFrBackWithNext() : nullptr;
|
||||||
|
AstNodeIf* const newifp
|
||||||
|
= new AstIf{itemp->fileline(),
|
||||||
|
new AstLte{condp->fileline(),
|
||||||
|
new AstVarRef{condp->fileline(), randVarp, VAccess::READ},
|
||||||
|
sump->cloneTree(true)},
|
||||||
|
stmtsp, nullptr};
|
||||||
|
ifsp->addElsesp(newifp);
|
||||||
|
ifsp = newifp;
|
||||||
|
}
|
||||||
|
AstDisplay* dispp = new AstDisplay{
|
||||||
|
fl, VDisplayType::DT_ERROR, "All randcase items had 0 weights (IEEE 1800-2017 18.16)",
|
||||||
|
nullptr, nullptr};
|
||||||
|
UASSERT_OBJ(m_modp, nodep, "randcase not under module");
|
||||||
|
dispp->fmtp()->timeunit(m_modp->timeunit());
|
||||||
|
ifsp->addElsesp(dispp);
|
||||||
|
|
||||||
|
AstNode* newp = randVarp;
|
||||||
|
AstNode* randp = new AstRand{fl, nullptr, false};
|
||||||
|
randp->dtypeSetUInt64();
|
||||||
|
newp->addNext(new AstAssign{fl, new AstVarRef{fl, randVarp, VAccess::WRITE},
|
||||||
|
new AstAdd{fl, new AstConst{fl, AstConst::Unsized64{}, 1},
|
||||||
|
new AstModDiv{fl, randp, sump}}});
|
||||||
|
newp->addNext(firstIfsp);
|
||||||
|
if (debug() >= 9) newp->dumpTreeAndNext(cout, "-rcnew: ");
|
||||||
|
nodep->replaceWith(newp);
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
|
}
|
||||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -4087,6 +4087,24 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void visit(AstRandCase* nodep) override {
|
||||||
|
// IEEE says each item is a int (32-bits), and sizes are based on natural sizing,
|
||||||
|
// but we'll sum to a 64-bit number then math is faster.
|
||||||
|
assertAtStatement(nodep);
|
||||||
|
v3Global.useRandomizeMethods(true);
|
||||||
|
AstNodeDType* const itemDTypep = nodep->findUInt32DType();
|
||||||
|
for (AstCaseItem *nextip, *itemp = nodep->itemsp(); itemp; itemp = nextip) {
|
||||||
|
nextip = VN_AS(itemp->nextp(), CaseItem); // Prelim may cause the node to get replaced
|
||||||
|
userIterateAndNext(itemp->stmtsp(), nullptr);
|
||||||
|
for (AstNode *nextcp, *condp = itemp->condsp(); condp; condp = nextcp) {
|
||||||
|
nextcp = condp->nextp(); // Prelim may cause the node to get replaced
|
||||||
|
iterateCheckTyped(itemp, "Randcase Item", condp, itemDTypep, BOTH);
|
||||||
|
VL_DANGLING(condp); // Might have been replaced
|
||||||
|
}
|
||||||
|
VL_DANGLING(itemp); // Might have been replaced
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void visit(AstNodeFor* nodep) override {
|
void visit(AstNodeFor* nodep) override {
|
||||||
assertAtStatement(nodep);
|
assertAtStatement(nodep);
|
||||||
userIterateAndNext(nodep->initsp(), nullptr);
|
userIterateAndNext(nodep->initsp(), nullptr);
|
||||||
|
|
|
||||||
|
|
@ -3369,8 +3369,7 @@ statement_item<nodep>: // IEEE: statement_item
|
||||||
//UNSUP randsequence_statement { $$ = $1; }
|
//UNSUP randsequence_statement { $$ = $1; }
|
||||||
//
|
//
|
||||||
// // IEEE: randcase_statement
|
// // IEEE: randcase_statement
|
||||||
| yRANDCASE case_itemList yENDCASE
|
| yRANDCASE rand_case_itemList yENDCASE { $$ = new AstRandCase{$1, $2}; }
|
||||||
{ $$ = nullptr; BBUNSUP($1, "Unsupported: SystemVerilog 2005 randcase statements"); }
|
|
||||||
//
|
//
|
||||||
//UNSUP expect_property_statement { $$ = $1; }
|
//UNSUP expect_property_statement { $$ = $1; }
|
||||||
//
|
//
|
||||||
|
|
@ -3527,6 +3526,12 @@ case_inside_itemList<caseItemp>: // IEEE: { case_inside_item + open_range
|
||||||
| case_inside_itemList yDEFAULT colon stmtBlock { $$ = $1->addNext(new AstCaseItem{$2, nullptr, $4}); }
|
| case_inside_itemList yDEFAULT colon stmtBlock { $$ = $1->addNext(new AstCaseItem{$2, nullptr, $4}); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
rand_case_itemList<caseItemp>: // IEEE: { rand_case_item + ... }
|
||||||
|
// // Randcase syntax doesn't have default, or expression lists
|
||||||
|
expr colon stmtBlock { $$ = new AstCaseItem{$2, $1, $3}; }
|
||||||
|
| rand_case_itemList expr colon stmtBlock { $$ = $1->addNext(new AstCaseItem{$3, $2, $4}); }
|
||||||
|
;
|
||||||
|
|
||||||
open_range_list<nodep>: // ==IEEE: open_range_list + open_value_range
|
open_range_list<nodep>: // ==IEEE: open_range_list + open_value_range
|
||||||
open_value_range { $$ = $1; }
|
open_value_range { $$ = $1; }
|
||||||
| open_range_list ',' open_value_range { $$ = $1->addNext($3); }
|
| open_range_list ',' open_value_range { $$ = $1->addNext($3); }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2020 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
|
||||||
|
|
||||||
|
scenarios(simulator => 1);
|
||||||
|
|
||||||
|
compile(
|
||||||
|
);
|
||||||
|
|
||||||
|
execute(
|
||||||
|
check_finished => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2022 by Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
`define check_range(gotv,minv,maxv) do if ((gotv) < (minv) || (gotv) > (maxv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d-%0d\n", `__FILE__,`__LINE__, (gotv), (minv), (maxv)); $stop; end while(0);
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/);
|
||||||
|
|
||||||
|
localparam int COUNT = 1000;
|
||||||
|
|
||||||
|
int v;
|
||||||
|
int counts[8];
|
||||||
|
|
||||||
|
initial begin;
|
||||||
|
|
||||||
|
//
|
||||||
|
for (int i = 0; i < 8; ++i) counts[i] = 0;
|
||||||
|
for (int i = 0; i < COUNT; ++i) begin
|
||||||
|
randcase
|
||||||
|
0 : ; // Never
|
||||||
|
0 : counts[0]++; // Never
|
||||||
|
1 : counts[1]++;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
`check_range(counts[0], 0, 0);
|
||||||
|
`check_range(counts[1], COUNT, COUNT);
|
||||||
|
|
||||||
|
//
|
||||||
|
for (int i = 0; i < 8; ++i) counts[i] = 0;
|
||||||
|
for (int i = 0; i < COUNT; ++i) begin
|
||||||
|
randcase
|
||||||
|
i - i : counts[0]++; // Never
|
||||||
|
i + i + 1: counts[1]++;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
`check_range(counts[0], 0, 0);
|
||||||
|
`check_range(counts[1], COUNT, COUNT);
|
||||||
|
|
||||||
|
//
|
||||||
|
for (int i = 0; i < 8; ++i) counts[i] = 0;
|
||||||
|
for (int i = 0; i < COUNT; ++i) begin
|
||||||
|
randcase
|
||||||
|
1 : counts[0]++; // Never
|
||||||
|
4 : counts[1]++;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
`check_range(counts[0], (COUNT * 1 / 5) * 70 / 100, (COUNT * 1 / 5) * 130 / 100);
|
||||||
|
`check_range(counts[1], (COUNT * 4 / 5) * 70 / 100, (COUNT * 4 / 5) * 130 / 100);
|
||||||
|
|
||||||
|
//
|
||||||
|
for (int i = 0; i < 8; ++i) counts[i] = 0;
|
||||||
|
for (int i = 0; i < COUNT; ++i) begin
|
||||||
|
randcase
|
||||||
|
2 : counts[0]++; // Never
|
||||||
|
2 : counts[1]++; // Never
|
||||||
|
1 : counts[2]++; // Never
|
||||||
|
1 : counts[3]++; // Never
|
||||||
|
1 : counts[4]++; // Never
|
||||||
|
1 : counts[5]++; // Never
|
||||||
|
1 : counts[6]++; // Never
|
||||||
|
1 : counts[7]++; // Never
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
`check_range(counts[0], (COUNT * 2 / 10) * 70 / 100, (COUNT * 2 / 10) * 130 / 100);
|
||||||
|
`check_range(counts[1], (COUNT * 2 / 10) * 70 / 100, (COUNT * 2 / 10) * 130 / 100);
|
||||||
|
`check_range(counts[2], (COUNT * 1 / 10) * 70 / 100, (COUNT * 1 / 10) * 130 / 100);
|
||||||
|
`check_range(counts[7], (COUNT * 1 / 10) * 70 / 100, (COUNT * 1 / 10) * 130 / 100);
|
||||||
|
|
||||||
|
//
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
[0] %Error: t_randcase_bad.v:12: Assertion failed in top.t.unnamedblk1: All randcase items had 0 weights (IEEE 1800-2017 18.16)
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2003 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
|
||||||
|
|
||||||
|
scenarios(vlt => 1);
|
||||||
|
|
||||||
|
compile(
|
||||||
|
);
|
||||||
|
|
||||||
|
execute(
|
||||||
|
expect_filename => $Self->{golden_filename},
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
// DESCRIPTION: Verilator: Test of select from constant
|
||||||
|
//
|
||||||
|
// This tests issue 508, bit select of constant fails
|
||||||
|
//
|
||||||
|
// This file ONLY is placed into the Public Domain, for any use,
|
||||||
|
// without warranty, 2022 by Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/);
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
randcase // Bad all zero weights
|
||||||
|
0 : $stop;
|
||||||
|
endcase
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue