Where in RTL does it get assigned?
From Verific Design Automation FAQ
Revision as of 13:06, 23 March 2021 by Hoa (Talk | contribs) (Created page with "This example illustrates how to find where a signal gets assigned in the RTL code. C++: <nowiki> #include <iostream> #include "veri_file.h" #include "VeriModule.h" #include...")
This example illustrates how to find where a signal gets assigned in the RTL code.
C++:
#include <iostream> #include "veri_file.h" #include "VeriModule.h" #include "VeriId.h" #include "VeriMisc.h" #include "VeriExpression.h" #include "veri_tokens.h" #include "VeriVisitor.h" #include "VeriStatement.h" #ifdef VERIFIC_NAMESPACE using namespace Verific ; #endif class MyVisitor : public VeriVisitor { public: MyVisitor() : VeriVisitor(), _assign(0) { } virtual ~MyVisitor() { _assign = 0 ; } virtual void VERI_VISIT(VeriIdRef, node) ; virtual void VERI_VISIT(VeriIndexedId, node) ; virtual void VERI_VISIT(VeriIndexedMemoryId, node) ; virtual void VERI_VISIT(VeriSelectedName, node) ; virtual void VERI_VISIT(VeriNetRegAssign, node) ; virtual void VERI_VISIT(VeriBlockingAssign, node) ; virtual void VERI_VISIT(VeriNonBlockingAssign, node) ; virtual void VERI_VISIT(VeriBinaryOperator, node) ; private: VeriTreeNode *_assign ; } ; // class MyVisitor void MyVisitor::VERI_VISIT(VeriIdRef, node) { VeriIdDef *id = node.GetId() ; if (!_assign || !id) return ; char *str = _assign->GetPrettyPrintedString() ; unsigned l = Strings::len(str) ; if (str && (str[l-1] == '\n')) str[l-1] = '\0' ; node.Info("%s is assigned here as: %s", id->Name(), str) ; Strings::free(str) ; } void MyVisitor::VERI_VISIT(VeriIndexedId, node) { // Call of Base class Visit VeriVisitor::VERI_VISIT_NODE(VeriName, node) ; TraverseNode(node.GetPrefix()) ; // Do not traverse the index! } void MyVisitor::VERI_VISIT(VeriIndexedMemoryId, node) { // Call of Base class Visit VeriVisitor::VERI_VISIT_NODE(VeriName, node) ; TraverseNode(node.GetPrefix()) ; // Do not traverse the index! } void MyVisitor::VERI_VISIT(VeriSelectedName, node) { VeriIdDef *id = node.GetId() ; if (!_assign || !id) return ; char *str = _assign->GetPrettyPrintedString() ; unsigned l = Strings::len(str) ; if (str && (str[l-1] == '\n')) str[l-1] = '\0' ; char *my_name = node.GetPrettyPrintedString() ; id->Info("%s is assigned here as: %s", my_name, str) ; Strings::free(my_name) ; Strings::free(str) ; } void MyVisitor::VERI_VISIT(VeriNetRegAssign, node) { // Call of Base class Visit VeriVisitor::VERI_VISIT_NODE(VeriTreeNode, node) ; VERIFIC_ASSERT(!_assign) ; // It should not be set here _assign = &node ; // Traverse the left hand side expression TraverseNode(node.GetLValExpr()) ; _assign = 0 ; // Trverse the right hand side expression TraverseNode(node.GetRValExpr()) ; } void MyVisitor::VERI_VISIT(VeriBlockingAssign, node) { // Call of Base class Visit VeriVisitor::VERI_VISIT_NODE(VeriStatement, node) ; VERIFIC_ASSERT(!_assign) ; // It should not be set here _assign = &node ; // Traverse left hand side of assignment TraverseNode(node.GetLVal()) ; // Pre increment decrement has right expression set, so do not reset it here: if ((node.OperType() != VERI_INC_OP) && (node.OperType() != VERI_DEC_OP)) _assign = 0 ; // Traverse the value of assignment TraverseNode(node.GetValue()) ; _assign = 0 ; // Traverse delay or event control TraverseNode(node.GetControl()) ; } void MyVisitor::VERI_VISIT(VeriNonBlockingAssign, node) { // Call of Base class Visit VeriVisitor::VERI_VISIT_NODE(VeriStatement, node) ; VERIFIC_ASSERT(!_assign) ; // It should not be set here _assign = &node ; // Traverse left hand side of assignment TraverseNode(node.GetLVal()) ; _assign = 0 ; // Traverse delay or event control TraverseNode(node.GetControl()) ; // Traverse the value TraverseNode(node.GetValue()) ; } void MyVisitor::VERI_VISIT(VeriBinaryOperator, node) { switch (node.OperType()) { case VERI_INC_OP : case VERI_DEC_OP : case VERI_PLUS_ASSIGN : case VERI_MIN_ASSIGN : case VERI_MUL_ASSIGN : case VERI_DIV_ASSIGN : case VERI_MOD_ASSIGN : case VERI_AND_ASSIGN : case VERI_OR_ASSIGN : case VERI_XOR_ASSIGN : case VERI_LSHIFT_ASSIGN : case VERI_RSHIFT_ASSIGN : case VERI_ALSHIFT_ASSIGN : case VERI_ARSHIFT_ASSIGN : case VERI_EQUAL_ASSIGN : break ; default: { // Not interested in this binary operator: VeriVisitor::VERI_VISIT_NODE(VeriBinaryOperator, node) ; return ; } } // Call of Base class Visit VeriVisitor::VERI_VISIT_NODE(VeriExpression, node) ; VERIFIC_ASSERT(!_assign) ; // It should not be set here _assign = &node ; // Traverse left operand TraverseNode(node.GetLeft()) ; // Pre increment decrement has right expression set, so do not reset it here: if ((node.OperType() != VERI_INC_OP) && (node.OperType() != VERI_DEC_OP)) _assign = 0 ; // Traverse right operand TraverseNode(node.GetRight()) ; _assign = 0 ; } int main(void) { if (!veri_file::Analyze("prep5.v", veri_file::SYSTEM_VERILOG, "work", veri_file::SFCU)) return 1 ; VeriModule *mod = veri_file::GetModule("prep5") ; if (!mod) return 2 ; MyVisitor mv ; mod->Accept(mv) ; return 0 ; }
Verilog testcase:
1 // PREP Benchmark 5, Arithmetic Circuit 2 /* PREP5 contains a multiplier and accumulator 3 Copyright (c) 1994 Synplicity, Inc. 4 You may distribute freely, as long as this header remains attached. */ 5 6 module prep5(Q, CLK, MAC, RST, A, B); 7 output [7:0] Q; 8 input CLK, MAC, RST; 9 input [3:0] A, B; 10 reg [7:0] Q; 11 wire [7:0] multiply_output; 12 wire [7:0] adder_output; 13 14 assign multiply_output = A * B; 15 assign adder_output = MAC ? multiply_output + Q : multiply_output; 16 17 always @(posedge CLK or posedge RST) 18 if (RST) 19 Q = 0; 20 else 21 Q = adder_output; 22 23 endmodule
Output:
-- Analyzing Verilog file 'prep5.v' (VERI-1482) prep5.v(14): INFO: multiply_output is assigned here as: multiply_output = (A * B) prep5.v(15): INFO: adder_output is assigned here as: adder_output = (MAC ? (multiply_output + Q) : multiply_output) prep5.v(19): INFO: Q is assigned here as: Q = 0 ; prep5.v(21): INFO: Q is assigned here as: Q = adder_output ;