Support `$past_gclk`

This commit is contained in:
Wilson Snyder 2025-07-01 18:00:04 -04:00
parent 7a3f1f16ca
commit 73ca2ab997
7 changed files with 60 additions and 51 deletions

View File

@ -460,7 +460,7 @@ private:
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
AstSenTree* sentreep = nodep->sentreep();
if (sentreep) sentreep->unlinkFrBack();
AstNodeExpr* const past = new AstPast{fl, exprp, nullptr};
AstNodeExpr* const past = new AstPast{fl, exprp};
past->dtypeFrom(exprp);
exprp = new AstAnd{fl, past, new AstNot{fl, exprp->cloneTreePure(false)}};
exprp->dtypeSetBit();
@ -481,7 +481,7 @@ private:
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
AstSenTree* sentreep = nodep->sentreep();
if (sentreep) sentreep->unlinkFrBack();
AstNodeExpr* const past = new AstPast{fl, exprp, nullptr};
AstNodeExpr* const past = new AstPast{fl, exprp};
past->dtypeFrom(exprp);
exprp = new AstAnd{fl, new AstNot{fl, past}, exprp->cloneTreePure(false)};
exprp->dtypeSetBit();
@ -496,7 +496,7 @@ private:
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
AstSenTree* sentreep = nodep->sentreep();
if (sentreep) sentreep->unlinkFrBack();
AstNodeExpr* const past = new AstPast{fl, exprp, nullptr};
AstNodeExpr* const past = new AstPast{fl, exprp};
past->dtypeFrom(exprp);
exprp = new AstEq{fl, past, exprp->cloneTreePure(false)};
exprp->dtypeSetBit();
@ -514,7 +514,7 @@ private:
if (m_disablep) lhsp = new AstAnd{fl, new AstNot{fl, m_disablep}, lhsp};
AstNodeExpr* const past = new AstPast{fl, lhsp, nullptr};
AstNodeExpr* const past = new AstPast{fl, lhsp};
past->dtypeFrom(lhsp);
AstNodeExpr* const exprp = new AstOr{fl, new AstNot{fl, past}, rhsp};
exprp->dtypeSetBit();

View File

@ -1732,10 +1732,12 @@ class AstPast final : public AstNodeExpr {
// @astgen op2 := ticksp : Optional[AstNode]
// @astgen op3 := sentreep : Optional[AstSenTree]
public:
AstPast(FileLine* fl, AstNodeExpr* exprp, AstNode* ticksp)
AstPast(FileLine* fl, AstNodeExpr* exprp, AstNode* ticksp = nullptr,
AstSenTree* sentreep = nullptr)
: ASTGEN_SUPER_Past(fl) {
this->exprp(exprp);
this->ticksp(ticksp);
this->sentreep(sentreep);
}
ASTGEN_MEMBERS_AstPast;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }

View File

@ -395,9 +395,13 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
void visit(AstPast* nodep) override {
putfs(nodep, "$past(");
iterateAndNextConstNull(nodep->exprp());
if (nodep->ticksp()) {
if (nodep->ticksp() || nodep->sentreep()) {
puts(", ");
iterateAndNextConstNull(nodep->ticksp());
if (nodep->sentreep()) {
puts(", ");
iterateAndNextConstNull(nodep->sentreep());
}
}
puts(")");
}

View File

@ -1356,6 +1356,7 @@ class WidthVisitor final : public VNVisitor {
}
}
}
userIterate(nodep->sentreep(), nullptr);
}
}
void visit(AstRose* nodep) override {

View File

@ -488,6 +488,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"$onehot" { FL; return yD_ONEHOT; }
"$onehot0" { FL; return yD_ONEHOT0; }
"$past" { FL; return yD_PAST; }
"$past_gclk" { FL; return yD_PAST_GCLK; }
"$right" { FL; return yD_RIGHT; }
"$root" { FL; return yD_ROOT; }
"$rose" { FL; return yD_ROSE; }

View File

@ -911,6 +911,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
%token<fl> yD_ONEHOT "$onehot"
%token<fl> yD_ONEHOT0 "$onehot0"
%token<fl> yD_PAST "$past"
%token<fl> yD_PAST_GCLK "$past_gclk"
%token<fl> yD_POW "$pow"
%token<fl> yD_PRINTTIMESCALE "$printtimescale"
%token<fl> yD_RANDOM "$random"
@ -4491,7 +4492,7 @@ system_f_call_or_t<nodeExprp>: // IEEE: part of system_tf_call (can be task
| yD_LOW '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_LOW, $3, $5}; }
| yD_ONEHOT '(' expr ')' { $$ = new AstOneHot{$1, $3}; }
| yD_ONEHOT0 '(' expr ')' { $$ = new AstOneHot0{$1, $3}; }
| yD_PAST '(' expr ')' { $$ = new AstPast{$1, $3, nullptr}; }
| yD_PAST '(' expr ')' { $$ = new AstPast{$1, $3}; }
| yD_PAST '(' expr ',' exprE ')' { $$ = new AstPast{$1, $3, $5}; }
| yD_PAST '(' expr ',' exprE ',' exprE ')'
{ if ($7) BBUNSUP($1, "Unsupported: $past expr2 and/or clock arguments");
@ -4499,6 +4500,7 @@ system_f_call_or_t<nodeExprp>: // IEEE: part of system_tf_call (can be task
| yD_PAST '(' expr ',' exprE ',' exprE ',' clocking_eventE ')'
{ if ($7 || $9) BBUNSUP($1, "Unsupported: $past expr2 and/or clock arguments");
$$ = new AstPast{$1, $3, $5}; }
| yD_PAST_GCLK '(' expr ')' { $$ = new AstPast{$1, $3, nullptr, GRAMMARP->createGlobalClockSenTree($1)}; }
| yD_POW '(' expr ',' expr ')' { $$ = new AstPowD{$1, $3, $5}; }
| yD_RANDOM '(' expr ')' { $$ = new AstRand{$1, $3, false}; }
| yD_RANDOM parenE { $$ = new AstRand{$1, nullptr, false}; }

View File

@ -5,9 +5,9 @@
// SPDX-License-Identifier: Unlicense
module t (/*AUTOARG*/
// Inputs
clk
);
// Inputs
clk
);
input clk;
integer cyc; initial cyc=1;
@ -41,16 +41,16 @@ module t (/*AUTOARG*/
endmodule
module Test (/*AUTOARG*/
// Inputs
clk, in
);
// Inputs
clk, in
);
input clk;
input [31:0] in;
reg [31:0] dly0 = 0;
reg [31:0] dly1 = 1;
reg [31:0] dly2 = -1;
reg [31:0] dly0 = 0;
reg [31:0] dly1 = 0;
reg [31:0] dly2 = 0;
// 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.
@ -60,33 +60,34 @@ module Test (/*AUTOARG*/
always @(posedge clk) begin
dly0 <= in;
dly1 <= in;
dly2 <= in;
dly1 <= dly0;
dly2 <= dly1;
// In clock expression
$write("in=%0d, dly0=%0d, rose=%0d, past=%0d\n", in, dly0, $rose(dly0), $past(dly0));
if ($rose(dly0[4])) $stop;
if ($fell(dly1[4])) $stop;
if ($stable(dly2)) $stop;
if (!$changed(dly2)) $stop;
if ($fell(dly0[4])) $stop;
if (!$stable(dly0[4])) $stop;
if ($changed(dly0[4])) $stop;
end
assert property (@(posedge clk) $rose(dly0) || dly0%2==0);
assert property (@(posedge clk) $fell(dly1) || dly1%2==1);
assert property (@(posedge clk) !$stable(dly2));
assert property (@(posedge clk) $changed(dly2));
assert property (@(posedge clk) $rose(dly0) || dly0%2==0 || dly2 < 3);
assert property (@(posedge clk) $fell(dly1) || dly1%2==1 || dly2 < 3);
assert property (@(posedge clk) !$stable(dly2) || dly2 < 3);
assert property (@(posedge clk) $changed(dly2) || dly2 < 3);
global clocking @(posedge clk); endclocking
always @ ($global_clock) $display("%d", in);
always @ ($global_clock) $display("gc in=%0d", in);
//
assert property (@(posedge clk) $rose(dly0, $global_clock) || dly0%2==0);
assert property (@(posedge clk) $fell(dly1, $global_clock) || dly1%2==1);
assert property (@(posedge clk) !$stable(dly2, $global_clock));
assert property (@(posedge clk) $changed(dly2, $global_clock));
assert property (@(posedge clk) $rose(dly0, $global_clock) || dly0%2==0 || dly2 < 3);
assert property (@(posedge clk) $fell(dly1, $global_clock) || dly1%2==1 || dly2 < 3);
assert property (@(posedge clk) !$stable(dly2, $global_clock) || dly2 < 3);
assert property (@(posedge clk) $changed(dly2, $global_clock) || dly2 < 3);
//
assert property (@(posedge clk) $rose_gclk(dly0) || dly0%2==0);
assert property (@(posedge clk) $fell_gclk(dly1) || dly1%2==1);
assert property (@(posedge clk) !$stable_gclk(dly2));
assert property (@(posedge clk) $changed_gclk(dly2));
assert property (@(posedge clk) $rose_gclk(dly0) || dly0%2==0 || dly2 < 3);
assert property (@(posedge clk) $fell_gclk(dly1) || dly1%2==1 || dly2 < 3);
assert property (@(posedge clk) $past_gclk(dly1) == dly2 || dly2 < 3);
assert property (@(posedge clk) !$stable_gclk(dly2) || dly2 < 3);
assert property (@(posedge clk) $changed_gclk(dly2) || dly2 < 3);
// global_clocking_future_functions are not supported yet:
// $changing_gclk global_clocking_future_function
@ -99,21 +100,21 @@ endmodule
module Test2 (/*AUTOARG*/
// Inputs
clk, in
);
// Inputs
clk, in
);
input clk;
input [31:0] in;
reg [31:0] dly0;
reg [31:0] dly1 = 1;
reg [31:0] dly2;
reg [31:0] dly0 = 0;
reg [31:0] dly1 = 0;
reg [31:0] dly2 = 0;
always @(posedge clk) begin
dly0 <= in;
dly1 <= in;
dly2 <= in;
dly1 <= dly0;
dly2 <= dly1;
if ($rose(dly0[31:4])) $stop;
if ($fell(dly1[31:4])) $stop;
if (!$stable(dly2[31:4])) $stop;
@ -122,23 +123,21 @@ module Test2 (/*AUTOARG*/
default clocking @(posedge clk); endclocking
assert property ($rose(dly0[0]) || dly0%2==0);
assert property ($fell(dly1[0]) || dly1%2==1);
assert property ($stable(dly2[31:4]));
assert property (!$changed(dly2[31:4]));
assert property ($rose(dly0[0]) || dly0%2==0 || dly2 < 3);
assert property ($fell(dly1[0]) || dly1%2==1 || dly2 < 3);
assert property ($stable(dly2[31:4]) || dly2 < 3);
assert property (!$changed(dly2[31:4]) || dly2 < 3);
endmodule
module Test3 (/*AUTOARG*/
// Inputs
clk, in
);
// Inputs
clk, in
);
input clk;
input [31:0] in;
// Check the named form of global clocking
global clocking gck @(posedge clk); endclocking
always @ (gck) $display("%d", in);
always @ ($global_clock) $display("%d", in);
endmodule