forked from github/verilator
Support $stable (#2488)
This commit is contained in:
parent
a52f975bd7
commit
1280070abb
1
Changes
1
Changes
@ -8,6 +8,7 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
**** Fix combining different-width parameters (#2484). [abirkmanis]
|
||||
|
||||
**** Support $stable. [Peter Monsson]
|
||||
|
||||
* Verilator 4.038 2020-07-11
|
||||
|
||||
|
@ -94,6 +94,21 @@ private:
|
||||
iterateChildren(nodep);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
}
|
||||
virtual void visit(AstStable* nodep) VL_OVERRIDE {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
iterateChildren(nodep);
|
||||
FileLine* fl = nodep->fileline();
|
||||
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
||||
AstNode* past = new AstPast(fl, exprp, NULL);
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstEq(fl, past,
|
||||
exprp->cloneTree(false)); // new AstVarRef(fl, exprp, true)
|
||||
exprp->dtypeSetLogicBool();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstPropClocked* nodep) VL_OVERRIDE {
|
||||
// No need to iterate the body, once replace will get iterated
|
||||
iterateAndNextNull(nodep->sensesp());
|
||||
|
@ -8015,6 +8015,31 @@ public:
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
};
|
||||
|
||||
class AstStable : public AstNodeMath {
|
||||
// Verilog $stable
|
||||
// Parents: math
|
||||
// Children: expression
|
||||
public:
|
||||
AstStable(FileLine* fl, AstNode* exprp)
|
||||
: ASTGEN_SUPER(fl) {
|
||||
addOp1p(exprp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(Stable)
|
||||
virtual string emitVerilog() { return "$stable(%l)"; }
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) {
|
||||
V3ERROR_NA;
|
||||
}
|
||||
virtual string emitC() { V3ERROR_NA_RETURN(""); }
|
||||
virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); }
|
||||
virtual bool cleanOut() const { V3ERROR_NA_RETURN(""); }
|
||||
virtual int instrCount() const { return widthInstrs(); }
|
||||
AstNode* exprp() const { return op1p(); } // op1 = expression
|
||||
AstSenTree* sentreep() const { return VN_CAST(op2p(), SenTree); } // op2 = clock domain
|
||||
void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
};
|
||||
|
||||
class AstPattern : public AstNodeMath {
|
||||
// Verilog '{a,b,c,d...}
|
||||
// Parents: AstNodeAssign, AstPattern, ...
|
||||
|
@ -1062,6 +1062,14 @@ private:
|
||||
nodep->dtypeFrom(nodep->exprp());
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstStable* nodep) VL_OVERRIDE {
|
||||
if (m_vup->prelim()) {
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
|
||||
nodep->dtypeSetLogicBool();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstRand* nodep) VL_OVERRIDE {
|
||||
if (m_vup->prelim()) {
|
||||
nodep->dtypeSetSigned32(); // Says the spec
|
||||
|
@ -435,6 +435,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
"$right" { FL; return yD_RIGHT; }
|
||||
"$root" { FL; return yD_ROOT; }
|
||||
"$size" { FL; return yD_SIZE; }
|
||||
"$stable" { FL; return yD_STABLE; }
|
||||
"$unpacked_dimensions" { FL; return yD_UNPACKED_DIMENSIONS; }
|
||||
"$warning" { FL; return yD_WARNING; }
|
||||
/* SV2005 Keywords */
|
||||
|
@ -771,6 +771,7 @@ BISONPRE_VERSION(3.0,%define parse.error verbose)
|
||||
%token<fl> yD_SIZE "$size"
|
||||
%token<fl> yD_SQRT "$sqrt"
|
||||
%token<fl> yD_SSCANF "$sscanf"
|
||||
%token<fl> yD_STABLE "$stable"
|
||||
%token<fl> yD_STIME "$stime"
|
||||
%token<fl> yD_STOP "$stop"
|
||||
%token<fl> yD_SWRITE "$swrite"
|
||||
@ -3648,6 +3649,8 @@ system_f_call_or_t<nodep>: // IEEE: part of system_tf_call (can be task or func)
|
||||
| yD_SQRT '(' expr ')' { $$ = new AstSqrtD($1,$3); }
|
||||
| yD_SSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstSScanF($1,*$5,$3,$6); }
|
||||
| yD_STIME parenE { $$ = new AstSel($1, new AstTime($1, VTimescale(VTimescale::NONE)), 0, 32); }
|
||||
| yD_STABLE '(' expr ')' { $$ = new AstStable($1,$3); }
|
||||
| yD_STABLE '(' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $stable and clock arguments"); }
|
||||
| yD_TAN '(' expr ')' { $$ = new AstTanD($1,$3); }
|
||||
| yD_TANH '(' expr ')' { $$ = new AstTanhD($1,$3); }
|
||||
| yD_TESTPLUSARGS '(' str ')' { $$ = new AstTestPlusArgs($1,*$3); }
|
||||
|
21
test_regress/t/t_stable.pl
Normal file
21
test_regress/t/t_stable.pl
Normal file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/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.
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
verilator_flags2 => ['--assert'],
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
81
test_regress/t/t_stable.v
Normal file
81
test_regress/t/t_stable.v
Normal file
@ -0,0 +1,81 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2020 by Peter Monsson.
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
|
||||
input clk;
|
||||
integer cyc; initial cyc=1;
|
||||
wire [31:0] in = cyc;
|
||||
|
||||
Test test (/*AUTOINST*/
|
||||
// Inputs
|
||||
.clk (clk),
|
||||
.in (in[31:0]));
|
||||
|
||||
Test2 test2 (/*AUTOINST*/
|
||||
// Inputs
|
||||
.clk (clk),
|
||||
.in (in[31:0]));
|
||||
|
||||
|
||||
always @ (posedge clk) begin
|
||||
if (cyc!=0) begin
|
||||
cyc <= cyc + 1;
|
||||
if (cyc==10) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module Test (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk, in
|
||||
);
|
||||
|
||||
input clk;
|
||||
input [31:0] in;
|
||||
|
||||
reg [31:0] dly0 = -1;
|
||||
|
||||
// If called in an assertion, sequence, or property, the appropriate clocking event.
|
||||
// Otherwise, if called in a disable condition or a clock expression in an assertion, sequence, or prop, explicit.
|
||||
// Otherwise, if called in an action block of an assertion, the leading clock of the assertion is used.
|
||||
// Otherwise, if called in a procedure, the inferred clock
|
||||
// Otherwise, default clocking
|
||||
|
||||
always @(posedge clk) begin
|
||||
dly0 <= in;
|
||||
// In clock expression
|
||||
$write("dly0=%0d, in=%0d, stable=%0d, past=%0d\n", dly0, in, $stable(dly0), $past(dly0));
|
||||
if ($stable(dly0)) $stop;
|
||||
end
|
||||
|
||||
assert property (@(posedge clk) !$stable(dly0));
|
||||
endmodule
|
||||
|
||||
module Test2 (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk, in
|
||||
);
|
||||
|
||||
input clk;
|
||||
input [31:0] in;
|
||||
|
||||
reg [31:0] dly0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
dly0 <= in;
|
||||
if (!$stable(dly0[31:4])) $stop;
|
||||
end
|
||||
|
||||
default clocking @(posedge clk); endclocking
|
||||
assert property ($stable(dly0[31:4]));
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user