Difference between revisions of "How to detect multiple-clock-edge condition in Verilog parsetree"

From Verific Design Automation FAQ
Jump to: navigation, search
(Created page with "Multiple-clock-edge condition is not support for synthesis. For example: always @(posedge clk or negedge clk) out <= in; or in SystemVerilog dialect: always @(ed...")
 
Line 18: Line 18:
  
 
  <nowiki>
 
  <nowiki>
 +
#include <iostream>
 
#include "veri_file.h"
 
#include "veri_file.h"
 
#include "VeriModule.h"
 
#include "VeriModule.h"
Line 38: Line 39:
 
     virtual void VERI_VISIT(VeriEventControlStatement, node)
 
     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() ;
 
         const Array *events = node.GetAt() ;
        unsigned multi_edges = 0 ;
 
 
         unsigned i ;
 
         unsigned i ;
 
         VeriExpression *event ;
 
         VeriExpression *event ;
         Set *posedges = new Set(STRING_HASH) ;
+
        VeriExpression *expr ;
 +
         Set posedges(STRING_HASH) ;
 
         FOREACH_ARRAY_ITEM(events, i, event) {
 
         FOREACH_ARRAY_ITEM(events, i, event) {
 
             if (!event) continue ;
 
             if (!event) continue ;
 
             if (event->GetEdgeToken() == VERI_EDGE) { // 'always @(edge clk)' is not synthesizable
 
             if (event->GetEdgeToken() == VERI_EDGE) { // 'always @(edge clk)' is not synthesizable
                 multi_edges = 1 ;
+
                 _multi_edge = 1 ;
 
                 break ;
 
                 break ;
 
             } else if (event->GetEdgeToken() == VERI_POSEDGE) { // populate 'posedges' set
 
             } else if (event->GetEdgeToken() == VERI_POSEDGE) { // populate 'posedges' set
                 const char *name = event->GetExpr()->GetPrettyPrintedString() ;
+
                 expr = event->GetExpr() ;
                 posedges->Insert(name) ;
+
                char *name = (expr) ? expr->GetPrettyPrintedString() : 0 ;
 +
                 (void) posedges.Insert(name) ;
 
             }
 
             }
 
         }
 
         }
         if (!multi_edges) {
+
         if (!_multi_edge) {
 
             FOREACH_ARRAY_ITEM(events, i, event) { // process 'negedge'
 
             FOREACH_ARRAY_ITEM(events, i, event) { // process 'negedge'
 
                 if (!event) continue ;
 
                 if (!event) continue ;
 
                 if (event->GetEdgeToken() == VERI_NEGEDGE) {
 
                 if (event->GetEdgeToken() == VERI_NEGEDGE) {
                     const char *name = event->GetExpr()->GetPrettyPrintedString() ;
+
                     expr = event->GetExpr() ;
                     if (posedges->GetItem(name)) { // already in 'posedges' set
+
                    char *name = (expr) ? expr->GetPrettyPrintedString() : 0 ;
                         multi_edges = 1 ;
+
                     if (posedges.GetItem(name)) { // already in 'posedges' set
 +
                         _multi_edge = 1 ;
 +
                        Strings::free(name) ;
 
                         break ;
 
                         break ;
 
                     }
 
                     }
 +
                    Strings::free(name) ;
 
                 }
 
                 }
 
             }
 
             }
 
         }
 
         }
         if (multi_edges) {
+
         SetIter si ;
            _multi_edge = 1 ;
+
        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.");
 
             Message::Msg(VERIFIC_INFO, 0, node.Linefile(), "Design has multi-edge always construct - not synthesizable.");
 
         }
 
         }
Line 72: Line 84:
  
 
     unsigned HasMultiEdge() const { return _multi_edge ; }
 
     unsigned HasMultiEdge() const { return _multi_edge ; }
 +
    void    Reset()              { _multi_edge = 0 ; }
  
 
protected:
 
protected:
Line 144: Line 157:
 
-- Analyzing Verilog file 'test.v' (VERI-1482)
 
-- Analyzing Verilog file 'test.v' (VERI-1482)
 
test.v(19): INFO: Design has multi-edge always construct - not synthesizable.
 
test.v(19): INFO: Design has multi-edge always construct - not synthesizable.
test.v(33): INFO: Design has multi-edge always construct - not synthesizable.
 
 
$
 
$
 
  </nowiki>
 
  </nowiki>

Revision as of 10:26, 11 June 2021

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 <iostream>
#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.
$