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