How to detect multiple-clock-edge condition in Verilog parsetree

From Verific Design Automation FAQ
Jump to: navigation, search

Multiple-clock-edge condition is not support for synthesis.

For example:

 always @(posedge clk or negedge clk)
     out <= in;

or in SystemVerilog dialect:

 always @(edge clk)
     out <= in;

Verific's parsers do not error out in analysis because these are perfectly legal Verilog/SystemVerilog. However, during RTL elaboration, Verific issues a warning message (that should be upgraded to an error):

 test.v(19): WARNING: assignment under multiple clock edges is not supported for synthesis (VERI-1466)

The code example below illustrates how to detect multiple-clock-edge conditions in the parsetree. Note that this example covers some common scenarios; it is not exhaustive. You need to adapt/expand it to your applications.

#include "veri_file.h"
#include "VeriModule.h"
#include "VeriStatement.h"
#include "VeriExpression.h"
#include "VeriVisitor.h"
#include "veri_tokens.h"
#include "Message.h"

#ifdef VERIFIC_NAMESPACE
using namespace Verific ;
#endif

class MyVisitor : public VeriVisitor
{
public:
    MyVisitor() : VeriVisitor(), _multi_edge(0) { }
    virtual ~MyVisitor() { }

    virtual void VERI_VISIT(VeriEventControlStatement, node)
    {
        // If you want to bail out after one multi-edge condition
        if (_multi_edge) return ; // Already found multiple edges
        // If you want to report all multi-edge conditions
        // Reset() ;

        const Array *events = node.GetAt() ;
        unsigned i ;
        VeriExpression *event ;
        VeriExpression *expr ;
        Set posedges(STRING_HASH) ;
        FOREACH_ARRAY_ITEM(events, i, event) {
            if (!event) continue ;
            if (event->GetEdgeToken() == VERI_EDGE) { // 'always @(edge clk)' is not synthesizable
                _multi_edge = 1 ;
                break ;
            } else if (event->GetEdgeToken() == VERI_POSEDGE) { // populate 'posedges' set
                expr = event->GetExpr() ;
                char *name = (expr) ? expr->GetPrettyPrintedString() : 0 ;
                (void) posedges.Insert(name) ;
            }
        }
        if (!_multi_edge) {
            FOREACH_ARRAY_ITEM(events, i, event) { // process 'negedge'
                if (!event) continue ;
                if (event->GetEdgeToken() == VERI_NEGEDGE) {
                    expr = event->GetExpr() ;
                    char *name = (expr) ? expr->GetPrettyPrintedString() : 0 ;
                    if (posedges.GetItem(name)) { // already in 'posedges' set
                        _multi_edge = 1 ;
                        Strings::free(name) ;
                        break ;
                    }
                    Strings::free(name) ;
                }
            }
        }
        SetIter si ;
        char *name ;
        FOREACH_SET_ITEM(&posedges, si, &name) Strings::free(name) ;
        if (_multi_edge) {
            Message::Msg(VERIFIC_INFO, 0, node.Linefile(), "Design has multi-edge always construct - not synthesizable.");
        }
    }

    unsigned HasMultiEdge() const { return _multi_edge ; }
    void     Reset()              { _multi_edge = 0 ; }

protected:
    unsigned _multi_edge ;
} ; // class MyVisitor

int main(void)
{
    // Analyze the design:
    if (!veri_file::Analyze("test.v", veri_file::SYSTEM_VERILOG)) return 1 ;

    // Get the module:
    VeriModule *top = veri_file::GetModule("top") ;
    if (!top) return 2 ;

    // Check for multi-edge always block:
    MyVisitor mv ;
    top->Accept(mv) ;

    if (mv.HasMultiEdge()) {
        return 3 ; // Bail out
    } ;

    // Otherwise, elaborate this design
    veri_file::ElaborateAll() ;

    return 0 ;
}
 

SystemVerilog testcase:

     1	module top ();
     2	    wire reset, set, in, clk;
     3	    reg out1, out2, out3, out4, out5;
     4	    // ok
     5	    always @(posedge reset or posedge set or posedge clk)
     6	        if (reset)
     7	            out1 <= 1'b0;
     8	        else if (set)
     9	            out1 <= 1'b1;
    10	        else
    11	            out1 <= in;
    12	    // not synthesizable
    13	    always @(negedge clk or posedge reset or posedge set or posedge clk)
    14	        if (reset)
    15	            out2 <= 1'b0;
    16	        else if (set)
    17	            out2 <= 1'b1;
    18	        else
    19	            out2 <= in;
    20	    // 'negedge clk' is repeated - ok
    21	    always @(negedge clk or posedge reset or posedge set or negedge clk)
    22	        if (reset)
    23	            out3 <= 1'b0;
    24	        else if (set)
    25	            out3 <= 1'b1;
    26	        else
    27	            out3 <= in;
    28	    // ok
    29	    always @(in)
    30	        out4 <= in;
    31	    // not synthesizable
    32	    always @(edge clk)
    33	        out5 <= in;
    34	endmodule
 

Run:

$ test-linux
-- Analyzing Verilog file 'test.v' (VERI-1482)
test.v(19): INFO: Design has multi-edge always construct - not synthesizable.
$