Where in RTL does 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(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() ;
node.Info("'%s' is assigned here as: %s", my_name, str) ;
Strings::free(my_name) ;
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(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("test.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 ;
}
Python script:
#!/usr/bin/python
import sys
sys.path.append('../py')
import Verific
class MyVisitor (Verific.VeriPythonVisitor) :
assign = 0
def __init__ (self) :
Verific.VeriPythonVisitor.__init__ (self, 0)
self.assign = 0
def VisitVeriIdRef (self, node) :
id = node.GetId()
if (not id or not self.assign) :
return
str = self.assign.GetPrettyPrintedString()
str = str.replace('\n', '')
node.Info("'" + id.Name() + "' is assigned here as: " + str)
def VisitVeriSelectedName (self, node) :
id = node.GetId()
if (not id or not self.assign) :
return
str = self.assign.GetPrettyPrintedString()
str = str.replace('\n', '')
my_name = node.GetPrettyPrintedString()
node.Info("'" + my_name + "' is assigned here as: " + str)
def VisitVeriIndexedId (self, node) :
# Call of Base class Visit
Verific.VeriPythonVisitor.VisitVeriName(self, node)
self.TraverseNode(node.GetPrefix())
# Do not traverse the index!
def VisitVeriIndexedMemoryId (self, node) :
# Call of Base class Visit
Verific.VeriPythonVisitor.VisitVeriName(self, node)
self.TraverseNode(node.GetPrefix())
# Do not traverse the index!
def VisitVeriNetRegAssign (self, node) :
# Call of Base class Visit
Verific.VeriPythonVisitor.VisitVeriTreeNode(self, node)
self.assign = node
self.TraverseNode(node.GetLValExpr())
self.assign = 0
self.TraverseNode(node.GetRValExpr())
def VisitVeriBlockingAssign (self, node) :
# Call of Base class Visit
Verific.VeriPythonVisitor.VisitVeriStatement(self, node)
self.assign = node
self.TraverseNode(node.GetLVal())
if ((node.OperType() != Verific.VERI_INC_OP) and (node.OperType() != Verific.VERI_DEC_OP)) :
self.assign = 0
self.TraverseNode(node.GetValue())
self.assign = 0
self.TraverseNode(node.GetControl())
def VisitVeriNonBlockingAssign (self, node) :
# Call of Base class Visit
Verific.VeriPythonVisitor.VisitVeriStatement(self, node)
self.assign = node
self.TraverseNode(node.GetLVal())
self.assign = 0
self.TraverseNode(node.GetValue())
self.TraverseNode(node.GetControl())
def VisitVeriBinaryOperator (self, node) :
if ((node.OperType() != Verific.VERI_INC_OP) and
(node.OperType() != Verific.VERI_DEC_OP) and
(node.OperType() != Verific.VERI_PLUS_ASSIGN) and
(node.OperType() != Verific.VERI_MIN_ASSIGN) and
(node.OperType() != Verific.VERI_MUL_ASSIGN) and
(node.OperType() != Verific.VERI_DIV_ASSIGN) and
(node.OperType() != Verific.VERI_MOD_ASSIGN) and
(node.OperType() != Verific.VERI_AND_ASSIGN) and
(node.OperType() != Verific.VERI_OR_ASSIGN) and
(node.OperType() != Verific.VERI_XOR_ASSIGN) and
(node.OperType() != Verific.VERI_LSHIFT_ASSIGN) and
(node.OperType() != Verific.VERI_RSHIFT_ASSIGN) and
(node.OperType() != Verific.VERI_ALSHIFT_ASSIGN) and
(node.OperType() != Verific.VERI_ARSHIFT_ASSIGN) and
(node.OperType() != Verific.VERI_EQUAL_ASSIGN)) :
# Not interested in this binary operator:
Verific.VeriPythonVisitor.VisitVeriBinaryOperator(self, node)
return
# Call of Base class Visit
Verific.VeriPythonVisitor.VisitVeriExpression(self, node)
self.assign = node
# Traverse left operand
self.TraverseNode(node.GetLeft())
# Pre increment decrement has right expression set, so do not reset it here:
if ((node.OperType() != Verific.VERI_INC_OP) and (node.OperType() != Verific.VERI_DEC_OP)) :
self.assign = 0
# Traverse right operand
self.TraverseNode(node.GetRight())
self.assign = 0
if (not Verific.veri_file_Analyze("test.v", Verific.veri_file.SYSTEM_VERILOG, "work", Verific.veri_file.SFCU)) :
exit (1)
mod = Verific.veri_file.GetModule("prep5")
if (not mod) :
exit (2)
mv = MyVisitor()
mv.Visit(mod)
exit (0)
Perl script:
#!/usr/bin/perl
use strict ;
push(@INC,"../pm") ;
require "Verific.pm" ;
package MyVisitor ;
our @ISA = "Verific::VeriPerlVisitor" ;
my $assign ;
sub new {
my ($class) = @_ ;
my $self = $class->SUPER::new() ;
$assign = 0 ;
bless $self, $class ;
return $self ;
}
sub VisitVeriIdRef : method {
my ($self, $node) = @_ ;
my $id = $node->GetId() ;
if (!$id || !$assign) { return ; }
my $str = $assign->GetPrettyPrintedString() ;
$str =~ s/\n//g ;
$node->Info("'" . $id->Name() . "' is assigned here as: " . $str) ;
}
sub VisitVeriSelectedName : method {
my ($self, $node) = @_ ;
my $id = $node->GetId() ;
if (!$id || !$assign) { return ; }
my $str = $assign->GetPrettyPrintedString() ;
$str =~ s/\n//g ;
my $my_name = $node->GetPrettyPrintedString() ;
$node->Info("'" . $my_name . "' is assigned here as: " . $str) ;
}
sub VisitVeriIndexedId : method {
my ($self, $node) = @_ ;
# Call of Base class Visit
$self->SUPER::VisitVeriName($node) ;
$self->TraverseNode($node->GetPrefix()) ;
# Do not traverse the index!
}
sub VisitVeriIndexedMemoryId : method {
my ($self, $node) = @_ ;
# Call of Base class Visit
$self->SUPER::VisitVeriName($node) ;
$self->TraverseNode($node->GetPrefix()) ;
# Do not traverse the index!
}
sub VisitVeriNetRegAssign : method {
my ($self, $node) = @_ ;
# Call of Base class Visit
$self->SUPER::VisitVeriTreeNode($node) ;
$assign = $node ;
$self->TraverseNode($node->GetLValExpr()) ;
$assign = 0 ;
$self->TraverseNode($node->GetRValExpr()) ;
}
sub VisitVeriBlockingAssign : method {
my ($self, $node) = @_ ;
# Call of Base class Visit
$self->SUPER::VisitVeriStatement($node) ;
$assign = $node ;
$self->TraverseNode($node->GetLVal()) ;
if (($node->OperType() != $Verific::VERI_INC_OP) && ($node->OperType() != $Verific::VERI_DEC_OP)) { $assign = 0 ; }
$self->TraverseNode($node->GetValue()) ;
$assign = 0 ;
$self->TraverseNode($node->GetControl()) ;
}
sub VisitVeriNonBlockingAssign : method {
my ($self, $node) = @_ ;
# Call of Base class Visit
$self->SUPER::VisitVeriStatement($node) ;
$assign = $node ;
$self->TraverseNode($node->GetLVal()) ;
$assign = 0 ;
$self->TraverseNode($node->GetValue()) ;
$self->TraverseNode($node->GetControl()) ;
}
sub VisitVeriBinaryOperator : method {
my ($self, $node) = @_ ;
if (!(($node->OperType() == $Verific::VERI_INC_OP) ||
($node->OperType() == $Verific::VERI_DEC_OP) ||
($node->OperType() == $Verific::VERI_PLUS_ASSIGN) ||
($node->OperType() == $Verific::VERI_MIN_ASSIGN) ||
($node->OperType() == $Verific::VERI_MUL_ASSIGN) ||
($node->OperType() == $Verific::VERI_DIV_ASSIGN) ||
($node->OperType() == $Verific::VERI_MOD_ASSIGN) ||
($node->OperType() == $Verific::VERI_AND_ASSIGN) ||
($node->OperType() == $Verific::VERI_OR_ASSIGN) ||
($node->OperType() == $Verific::VERI_XOR_ASSIGN) ||
($node->OperType() == $Verific::VERI_LSHIFT_ASSIGN) ||
($node->OperType() == $Verific::VERI_RSHIFT_ASSIGN) ||
($node->OperType() == $Verific::VERI_ALSHIFT_ASSIGN) ||
($node->OperType() == $Verific::VERI_ARSHIFT_ASSIGN) ||
($node->OperType() == $Verific::VERI_EQUAL_ASSIGN))) {
# Not interested in this binary operator:
$self->SUPER::VisitVeriBinaryOperator($node) ;
return ;
}
# Call of Base class Visit
$self->SUPER::VisitVeriExpression($node) ;
$assign = $node ;
# Traverse left operand
$self->TraverseNode($node->GetLeft()) ;
# Pre increment decrement has right expression set, so do not reset it here:
if (($node->OperType() != $Verific::VERI_INC_OP) && ($node->OperType() != $Verific::VERI_DEC_OP)) { $assign = 0 ; }
# Traverse right operand
$self->TraverseNode($node->GetRight()) ;
$assign = 0 ;
}
1 ;
if (!Verific::veri_file::Analyze("test.v", $Verific::veri_file::SYSTEM_VERILOG, "work", $Verific::veri_file::SFCU)) { exit (1) ; }
my $mod = Verific::veri_file::GetModule("prep5") ;
if (!$mod) { exit (2) ; }
my $mv = MyVisitor->new() ;
$mv->Visit($mod) ;
exit (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 wire [7:0] func_out;
14
15 assign multiply_output = A * B;
16 assign adder_output = MAC ? multiply_output + Q : multiply_output;
17
18 always @(posedge CLK or posedge RST)
19 if (RST)
20 Q <= 0;
21 else
22 Q <= adder_output;
23
24 assign func_out = fn1(0) ;
25
26 function [7:0] fn1(input integer a) ;
27 integer b ;
28 b = a++ ;
29 b++ ;
30 ++b ;
31 b += (b = b+2) ;
32 return b ;
33 endfunction
34 endmodule
Output:
-- Analyzing Verilog file 'test.v' (VERI-1482) test.v(15): INFO: 'multiply_output' is assigned here as: multiply_output = (A * B) test.v(16): INFO: 'adder_output' is assigned here as: adder_output = (MAC ? (multiply_output + Q) : multiply_output) test.v(20): INFO: 'Q' is assigned here as: Q <= 0 ; test.v(22): INFO: 'Q' is assigned here as: Q <= adder_output ; test.v(24): INFO: 'func_out' is assigned here as: func_out = fn1(0) test.v(28): INFO: 'b' is assigned here as: b = (a ++ ) ; test.v(28): INFO: 'a' is assigned here as: (a ++ ) test.v(29): INFO: 'b' is assigned here as: b ++ ; test.v(30): INFO: 'b' is assigned here as: ++ b ; test.v(31): INFO: 'b' is assigned here as: b += (b = (b + 2)) ; test.v(31): INFO: 'b' is assigned here as: (b = (b + 2))