Support $changed_gclk, $fell_gclk, $rose_gclk, $stable_gclk

This commit is contained in:
Wilson Snyder 2023-01-28 14:05:26 -05:00
parent f20997a2f0
commit ba8700f99d
9 changed files with 72 additions and 79 deletions

View File

@ -63,9 +63,10 @@ private:
// METHODS
AstSenTree* newSenTree(AstNode* nodep) {
AstSenTree* newSenTree(AstNode* nodep, AstSenTree* useTreep = nullptr) {
// Create sentree based on clocked or default clock
// Return nullptr for always
if (useTreep) return useTreep;
AstSenTree* newp = nullptr;
AstSenItem* senip = m_senip;
if (!senip && m_defaultClockingp) senip = m_defaultClockingp->sensesp();
@ -362,17 +363,19 @@ private:
clearAssertInfo();
}
void visit(AstFell* nodep) override {
if (nodep->sentreep()) return; // Already processed
if (nodep->user1SetOnce()) return;
iterateChildren(nodep);
FileLine* const fl = nodep->fileline();
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
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};
past->dtypeFrom(exprp);
exprp = new AstAnd{fl, past, new AstNot{fl, exprp->cloneTree(false)}};
exprp->dtypeSetBit();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep));
nodep->sentreep(newSenTree(nodep, sentreep));
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
void visit(AstPast* nodep) override {
@ -381,30 +384,34 @@ private:
nodep->sentreep(newSenTree(nodep));
}
void visit(AstRose* nodep) override {
if (nodep->sentreep()) return; // Already processed
if (nodep->user1SetOnce()) return;
iterateChildren(nodep);
FileLine* const fl = nodep->fileline();
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
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};
past->dtypeFrom(exprp);
exprp = new AstAnd{fl, new AstNot{fl, past}, exprp->cloneTree(false)};
exprp->dtypeSetBit();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep));
nodep->sentreep(newSenTree(nodep, sentreep));
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
void visit(AstStable* nodep) override {
if (nodep->sentreep()) return; // Already processed
if (nodep->user1SetOnce()) return;
iterateChildren(nodep);
FileLine* const fl = nodep->fileline();
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
AstSenTree* sentreep = nodep->sentreep();
if (sentreep) sentreep->unlinkFrBack();
AstNodeExpr* const past = new AstPast{fl, exprp, nullptr};
past->dtypeFrom(exprp);
exprp = new AstEq{fl, past, exprp->cloneTree(false)};
exprp->dtypeSetBit();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep));
nodep->sentreep(newSenTree(nodep, sentreep));
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}

View File

@ -1183,9 +1183,10 @@ class AstFell final : public AstNodeExpr {
// @astgen op1 := exprp : AstNodeExpr
// @astgen op2 := sentreep : Optional[AstSenTree]
public:
AstFell(FileLine* fl, AstNodeExpr* exprp)
AstFell(FileLine* fl, AstNodeExpr* exprp, AstSenTree* sentreep)
: ASTGEN_SUPER_Fell(fl) {
this->exprp(exprp);
this->sentreep(sentreep);
}
ASTGEN_MEMBERS_AstFell;
string emitVerilog() override { return "$fell(%l)"; }
@ -1536,9 +1537,10 @@ class AstRose final : public AstNodeExpr {
// @astgen op1 := exprp : AstNodeExpr
// @astgen op2 := sentreep : Optional[AstSenTree]
public:
AstRose(FileLine* fl, AstNodeExpr* exprp)
AstRose(FileLine* fl, AstNodeExpr* exprp, AstSenTree* sentreep)
: ASTGEN_SUPER_Rose(fl) {
this->exprp(exprp);
this->sentreep(sentreep);
}
ASTGEN_MEMBERS_AstRose;
string emitVerilog() override { return "$rose(%l)"; }
@ -1754,9 +1756,10 @@ class AstStable final : public AstNodeExpr {
// @astgen op1 := exprp : AstNodeExpr
// @astgen op2 := sentreep : Optional[AstSenTree]
public:
AstStable(FileLine* fl, AstNodeExpr* exprp)
AstStable(FileLine* fl, AstNodeExpr* exprp, AstSenTree* sentreep)
: ASTGEN_SUPER_Stable(fl) {
this->exprp(exprp);
this->sentreep(sentreep);
}
ASTGEN_MEMBERS_AstStable;
string emitVerilog() override { return "$stable(%l)"; }

View File

@ -1177,6 +1177,7 @@ private:
void visit(AstFell* nodep) override {
if (m_vup->prelim()) {
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
userIterate(nodep->sentreep(), nullptr);
nodep->dtypeSetBit();
}
}
@ -1207,6 +1208,7 @@ private:
void visit(AstRose* nodep) override {
if (m_vup->prelim()) {
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
userIterate(nodep->sentreep(), nullptr);
nodep->dtypeSetBit();
}
}
@ -1221,6 +1223,7 @@ private:
void visit(AstStable* nodep) override {
if (m_vup->prelim()) {
iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
userIterate(nodep->sentreep(), nullptr);
nodep->dtypeSetBit();
}
}

View File

@ -460,12 +460,14 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
/* System Tasks */
"$bits" { FL; return yD_BITS; }
"$changed" { FL; return yD_CHANGED; }
"$changed_gclk" { FL; return yD_CHANGED_GCLK; }
"$countbits" { FL; return yD_COUNTBITS; }
"$countones" { FL; return yD_COUNTONES; }
"$dimensions" { FL; return yD_DIMENSIONS; }
"$error" { FL; return yD_ERROR; }
"$fatal" { FL; return yD_FATAL; }
"$fell" { FL; return yD_FELL; }
"$fell_gclk" { FL; return yD_FELL_GCLK; }
"$high" { FL; return yD_HIGH; }
"$increment" { FL; return yD_INCREMENT; }
"$info" { FL; return yD_INFO; }
@ -479,8 +481,10 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"$right" { FL; return yD_RIGHT; }
"$root" { FL; return yD_ROOT; }
"$rose" { FL; return yD_ROSE; }
"$rose_gclk" { FL; return yD_ROSE_GCLK; }
"$size" { FL; return yD_SIZE; }
"$stable" { FL; return yD_STABLE; }
"$stable_gclk" { FL; return yD_STABLE_GCLK; }
"$unpacked_dimensions" { FL; return yD_UNPACKED_DIMENSIONS; }
"$warning" { FL; return yD_WARNING; }
/* SV2005 Keywords */

View File

@ -168,6 +168,15 @@ public:
return new AstGatePin{rangep->fileline(), exprp, rangep->cloneTree(true)};
}
}
AstSenTree* createClockSenTree(FileLine* fl, AstNodeExpr* exprp) {
return new AstSenTree{fl, new AstSenItem{fl, VEdgeType::ET_CHANGED, exprp}};
}
AstNodeExpr* createGlobalClockParseRef(FileLine* fl) {
return new AstParseRef{fl, VParseRefExp::PX_TEXT, "__024global_clock", nullptr, nullptr};
}
AstSenTree* createGlobalClockSenTree(FileLine* fl) {
return createClockSenTree(fl, createGlobalClockParseRef(fl));
}
AstNode* createTypedef(FileLine* fl, const string& name, AstNode* attrsp, AstNodeDType* basep,
AstNodeRange* rangep) {
AstNode* const nodep = new AstTypedef{fl, name, attrsp, VFlagChildDType{},
@ -784,6 +793,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
%token<fl> yD_CAST "$cast"
%token<fl> yD_CEIL "$ceil"
%token<fl> yD_CHANGED "$changed"
%token<fl> yD_CHANGED_GCLK "$changed_gclk"
%token<fl> yD_CLOG2 "$clog2"
%token<fl> yD_COS "$cos"
%token<fl> yD_COSH "$cosh"
@ -819,6 +829,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
%token<fl> yD_FDISPLAYH "$fdisplayh"
%token<fl> yD_FDISPLAYO "$fdisplayo"
%token<fl> yD_FELL "$fell"
%token<fl> yD_FELL_GCLK "$fell_gclk"
%token<fl> yD_FEOF "$feof"
%token<fl> yD_FERROR "$ferror"
%token<fl> yD_FFLUSH "$fflush"
@ -876,6 +887,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
%token<fl> yD_RIGHT "$right"
%token<fl> yD_ROOT "$root"
%token<fl> yD_ROSE "$rose"
%token<fl> yD_ROSE_GCLK "$rose_gclk"
%token<fl> yD_RTOI "$rtoi"
%token<fl> yD_SAMPLED "$sampled"
%token<fl> yD_SFORMAT "$sformat"
@ -888,6 +900,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
%token<fl> yD_SQRT "$sqrt"
%token<fl> yD_SSCANF "$sscanf"
%token<fl> yD_STABLE "$stable"
%token<fl> yD_STABLE_GCLK "$stable_gclk"
%token<fl> yD_STACKTRACE "$stacktrace"
%token<fl> yD_STIME "$stime"
%token<fl> yD_STOP "$stop"
@ -4067,8 +4080,11 @@ system_f_call_or_t<nodeExprp>: // IEEE: part of system_tf_call (can be task
| yD_BITSTOREAL '(' expr ')' { $$ = new AstBitsToRealD{$1, $3}; }
| yD_BITSTOSHORTREAL '(' expr ')' { $$ = new AstBitsToRealD{$1, $3}; UNSUPREAL($1); }
| yD_CEIL '(' expr ')' { $$ = new AstCeilD{$1, $3}; }
| yD_CHANGED '(' expr ')' { $$ = new AstLogNot{$1, new AstStable{$1, $3}}; }
| yD_CHANGED '(' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $changed and clock arguments"); }
| yD_CHANGED '(' expr ')' { $$ = new AstLogNot{$1, new AstStable{$1, $3, nullptr}}; }
| yD_CHANGED '(' expr ',' expr ')'
{ $$ = new AstLogNot{$1, new AstStable{$1, $3, GRAMMARP->createClockSenTree($1, $5)}}; }
| yD_CHANGED_GCLK '(' expr ')'
{ $$ = new AstLogNot{$1, new AstStable{$1, $3, GRAMMARP->createGlobalClockSenTree($1)}}; }
| yD_CLOG2 '(' expr ')' { $$ = new AstCLog2{$1, $3}; }
| yD_COS '(' expr ')' { $$ = new AstCosD{$1, $3}; }
| yD_COSH '(' expr ')' { $$ = new AstCoshD{$1, $3}; }
@ -4088,8 +4104,9 @@ system_f_call_or_t<nodeExprp>: // IEEE: part of system_tf_call (can be task
| yD_DIST_T '(' expr ',' expr ')' { $$ = new AstDistT{$1, $3, $5}; }
| yD_DIST_UNIFORM '(' expr ',' expr ',' expr ')' { $$ = new AstDistUniform{$1, $3, $5, $7}; }
| yD_EXP '(' expr ')' { $$ = new AstExpD{$1, $3}; }
| yD_FELL '(' expr ')' { $$ = new AstFell{$1, $3}; }
| yD_FELL '(' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $fell and clock arguments"); }
| yD_FELL '(' expr ')' { $$ = new AstFell{$1, $3, nullptr}; }
| yD_FELL '(' expr ',' expr ')' { $$ = new AstFell{$1, $3, GRAMMARP->createClockSenTree($1, $5)}; }
| yD_FELL_GCLK '(' expr ')' { $$ = new AstFell{$1, $3, GRAMMARP->createGlobalClockSenTree($1)}; }
| yD_FEOF '(' expr ')' { $$ = new AstFEof{$1, $3}; }
| yD_FERROR '(' idClassSel ',' idClassSel ')' { $$ = new AstFError{$1, $3, $5}; }
| yD_FGETC '(' expr ')' { $$ = new AstFGetC{$1, $3}; }
@ -4102,8 +4119,7 @@ system_f_call_or_t<nodeExprp>: // IEEE: part of system_tf_call (can be task
| yD_FSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstFScanF{$1, *$5, $3, $6}; }
| yD_FSEEK '(' idClassSel ',' expr ',' expr ')' { $$ = new AstFSeek{$1, $3, $5, $7}; }
| yD_FTELL '(' idClassSel ')' { $$ = new AstFTell{$1, $3}; }
| yD_GLOBAL_CLOCK parenE
{ $$ = new AstParseRef{$<fl>1, VParseRefExp::PX_TEXT, "__024global_clock", nullptr, nullptr}; }
| yD_GLOBAL_CLOCK parenE { $$ = GRAMMARP->createGlobalClockParseRef($1); }
| yD_HIGH '(' exprOrDataType ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_HIGH, $3, nullptr}; }
| yD_HIGH '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_HIGH, $3, $5}; }
| yD_HYPOT '(' expr ',' expr ')' { $$ = new AstHypotD{$1, $3, $5}; }
@ -4134,8 +4150,9 @@ system_f_call_or_t<nodeExprp>: // IEEE: part of system_tf_call (can be task
| yD_REWIND '(' idClassSel ')' { $$ = new AstFSeek{$1, $3, new AstConst{$1, 0}, new AstConst{$1, 0}}; }
| yD_RIGHT '(' exprOrDataType ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_RIGHT, $3, nullptr}; }
| yD_RIGHT '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_RIGHT, $3, $5}; }
| yD_ROSE '(' expr ')' { $$ = new AstRose{$1, $3}; }
| yD_ROSE '(' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $rose and clock arguments"); }
| yD_ROSE '(' expr ')' { $$ = new AstRose{$1, $3, nullptr}; }
| yD_ROSE '(' expr ',' expr ')' { $$ = new AstRose{$1, $3, GRAMMARP->createClockSenTree($1, $5)}; }
| yD_ROSE_GCLK '(' expr ')' { $$ = new AstRose{$1, $3, GRAMMARP->createGlobalClockSenTree($1)}; }
| yD_RTOI '(' expr ')' { $$ = new AstRToIS{$1, $3}; }
| yD_SAMPLED '(' expr ')' { $$ = new AstSampled{$1, $3}; }
| yD_SFORMATF '(' exprDispList ')' { $$ = new AstSFormatF{$1, AstSFormatF::NoFormat{}, $3, 'd', false}; }
@ -4149,8 +4166,9 @@ system_f_call_or_t<nodeExprp>: // IEEE: part of system_tf_call (can be task
| 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_STABLE '(' expr ')' { $$ = new AstStable{$1, $3, nullptr}; }
| yD_STABLE '(' expr ',' expr ')' { $$ = new AstStable{$1, $3, GRAMMARP->createClockSenTree($1, $5)}; }
| yD_STABLE_GCLK '(' expr ')' { $$ = new AstStable{$1, $3, GRAMMARP->createGlobalClockSenTree($1)}; }
| yD_TAN '(' expr ')' { $$ = new AstTanD{$1, $3}; }
| yD_TANH '(' expr ')' { $$ = new AstTanhD{$1, $3}; }
| yD_TESTPLUSARGS '(' expr ')' { $$ = new AstTestPlusArgs{$1, $3}; }

View File

@ -77,6 +77,23 @@ module Test (/*AUTOARG*/
global clocking @(posedge clk); endclocking
always @ ($global_clock) $display("%d", 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_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));
// global_clocking_future_functions are not supported yet:
// $changing_gclk global_clocking_future_function
// $falling_gclk global_clocking_future_function
// $future_gclk global_clocking_future_function
// $rising_gclk global_clocking_future_function
// $steady_gclk global_clocking_future_function
endmodule

View File

@ -1,20 +0,0 @@
%Error-UNSUPPORTED: t/t_past_unsup_bad.v:13:11: Unsupported: $past expr2 and clock arguments
13 | if ($past(d, 0, 0)) $stop;
| ^~~~~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error-UNSUPPORTED: t/t_past_unsup_bad.v:14:11: Unsupported: $past expr2 and clock arguments
14 | if ($past(d, 0, 0, clk)) $stop;
| ^~~~~
%Error-UNSUPPORTED: t/t_past_unsup_bad.v:15:11: Unsupported: $fell and clock arguments
15 | if ($fell(d, clk)) $stop;
| ^~~~~
%Error-UNSUPPORTED: t/t_past_unsup_bad.v:16:11: Unsupported: $rose and clock arguments
16 | if ($rose(d, clk)) $stop;
| ^~~~~
%Error-UNSUPPORTED: t/t_past_unsup_bad.v:17:11: Unsupported: $stable and clock arguments
17 | if ($stable(d, clk)) $stop;
| ^~~~~~~
%Error-UNSUPPORTED: t/t_past_unsup_bad.v:18:11: Unsupported: $changed and clock arguments
18 | if ($changed(d, clk)) $stop;
| ^~~~~~~~
%Error: Exiting due to

View File

@ -1,19 +0,0 @@
#!/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);
lint(
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -1,20 +0,0 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2018 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
module t (d, clk);
input d;
input clk;
always @ (posedge clk) begin
// Unsupported
if ($past(d, 0, 0)) $stop;
if ($past(d, 0, 0, clk)) $stop;
if ($fell(d, clk)) $stop;
if ($rose(d, clk)) $stop;
if ($stable(d, clk)) $stop;
if ($changed(d, clk)) $stop;
end
endmodule