From 1280070abbca1a2999c2974193701c0240aeda32 Mon Sep 17 00:00:00 2001 From: Peter Monsson Date: Wed, 29 Jul 2020 00:26:24 +0200 Subject: [PATCH] Support $stable (#2488) --- Changes | 1 + src/V3AssertPre.cpp | 15 +++++++ src/V3AstNodes.h | 25 ++++++++++++ src/V3Width.cpp | 8 ++++ src/verilog.l | 1 + src/verilog.y | 3 ++ test_regress/t/t_stable.pl | 21 ++++++++++ test_regress/t/t_stable.v | 81 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 155 insertions(+) create mode 100644 test_regress/t/t_stable.pl create mode 100644 test_regress/t/t_stable.v diff --git a/Changes b/Changes index 693739918..7f929b62d 100644 --- a/Changes +++ b/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 diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp index 6448d0eab..0d5859704 100644 --- a/src/V3AssertPre.cpp +++ b/src/V3AssertPre.cpp @@ -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()); diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index b93f0d014..474d6a31f 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -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, ... diff --git a/src/V3Width.cpp b/src/V3Width.cpp index de04c0a82..90c358710 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -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 diff --git a/src/verilog.l b/src/verilog.l index c309be3fd..7d4d5c843 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -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 */ diff --git a/src/verilog.y b/src/verilog.y index b8d9f2cb8..1c65e6496 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -771,6 +771,7 @@ BISONPRE_VERSION(3.0,%define parse.error verbose) %token yD_SIZE "$size" %token yD_SQRT "$sqrt" %token yD_SSCANF "$sscanf" +%token yD_STABLE "$stable" %token yD_STIME "$stime" %token yD_STOP "$stop" %token yD_SWRITE "$swrite" @@ -3648,6 +3649,8 @@ system_f_call_or_t: // 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); } diff --git a/test_regress/t/t_stable.pl b/test_regress/t/t_stable.pl new file mode 100644 index 000000000..c1a6773e9 --- /dev/null +++ b/test_regress/t/t_stable.pl @@ -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; diff --git a/test_regress/t/t_stable.v b/test_regress/t/t_stable.v new file mode 100644 index 000000000..9b9a831b7 --- /dev/null +++ b/test_regress/t/t_stable.v @@ -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