How to detect multiple-clock-edge condition in Verilog parsetree
From Verific Design Automation FAQ
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. $