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