Where in RTL is it get assigned?
From Verific Design Automation FAQ
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 ;