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

From Verific Design Automation FAQ
Revision as of 10:56, 9 June 2021 by Hoa (Talk | contribs) (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...")

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
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)
    {
        const Array *events = node.GetAt() ;
        unsigned multi_edges = 0 ;
        unsigned i ;
        VeriExpression *event ;
        Set *posedges = new Set(STRING_HASH) ;
        FOREACH_ARRAY_ITEM(events, i, event) {
            if (!event) continue ;
            if (event->GetEdgeToken() == VERI_EDGE) { // 'always @(edge clk)' is not synthesizable
                multi_edges = 1 ;
                break ;
            } else if (event->GetEdgeToken() == VERI_POSEDGE) { // populate 'posedges' set
                const char *name = event->GetExpr()->GetPrettyPrintedString() ;
                posedges->Insert(name) ;
            }
        }
        if (!multi_edges) {
            FOREACH_ARRAY_ITEM(events, i, event) { // process 'negedge'
                if (!event) continue ;
                if (event->GetEdgeToken() == VERI_NEGEDGE) {
                    const char *name = event->GetExpr()->GetPrettyPrintedString() ;
                    if (posedges->GetItem(name)) { // already in 'posedges' set
                        multi_edges = 1 ;
                        break ;
                    }
                }
            }
        }
        if (multi_edges) {
            _multi_edge = 1 ;
            Message::Msg(VERIFIC_INFO, 0, node.Linefile(), "Design has multi-edge always construct - not synthesizable.");
        }
    }

    unsigned HasMultiEdge() const { return _multi_edge ; }

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.
test.v(33): INFO: Design has multi-edge always construct - not synthesizable.
$