Difference between revisions of "Where in RTL does it get assigned?"

From Verific Design Automation FAQ
Jump to: navigation, search
(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...")
 
 
Line 47: Line 47:
 
     unsigned l = Strings::len(str) ;
 
     unsigned l = Strings::len(str) ;
 
     if (str && (str[l-1] == '\n')) str[l-1] = '\0' ;
 
     if (str && (str[l-1] == '\n')) str[l-1] = '\0' ;
     node.Info("%s is assigned here as: %s", id->Name(), str) ;
+
     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) ;
 
     Strings::free(str) ;
 
}
 
}
Line 56: Line 71:
 
     // Call of Base class Visit
 
     // Call of Base class Visit
 
     VeriVisitor::VERI_VISIT_NODE(VeriName, node) ;
 
     VeriVisitor::VERI_VISIT_NODE(VeriName, node) ;
 +
 
     TraverseNode(node.GetPrefix()) ;
 
     TraverseNode(node.GetPrefix()) ;
 +
 
     // Do not traverse the index!
 
     // Do not traverse the index!
 
}
 
}
Line 65: Line 82:
 
     // Call of Base class Visit
 
     // Call of Base class Visit
 
     VeriVisitor::VERI_VISIT_NODE(VeriName, node) ;
 
     VeriVisitor::VERI_VISIT_NODE(VeriName, node) ;
 +
 
     TraverseNode(node.GetPrefix()) ;
 
     TraverseNode(node.GetPrefix()) ;
 +
 
     // Do not traverse the index!
 
     // 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) ;
 
 
}
 
}
  
Line 194: Line 198:
 
int main(void)
 
int main(void)
 
{
 
{
     if (!veri_file::Analyze("prep5.v", veri_file::SYSTEM_VERILOG, "work", veri_file::SFCU)) return 1 ;
+
     if (!veri_file::Analyze("test.v", veri_file::SYSTEM_VERILOG, "work", veri_file::SFCU)) return 1 ;
 +
 
 
     VeriModule *mod = veri_file::GetModule("prep5") ;
 
     VeriModule *mod = veri_file::GetModule("prep5") ;
 
     if (!mod) return 2 ;
 
     if (!mod) return 2 ;
Line 203: Line 208:
 
     return 0 ;
 
     return 0 ;
 
}
 
}
 +
</nowiki>
 +
 +
Python script:
 +
 +
<nowiki>
 +
#!/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)
 +
</nowiki>
 +
 +
Perl script:
 +
 +
<nowiki>
 +
#!/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) ;
 
  </nowiki>
 
  </nowiki>
  
Line 220: Line 534:
 
     11   wire [7:0] multiply_output;
 
     11   wire [7:0] multiply_output;
 
     12   wire [7:0] adder_output;
 
     12   wire [7:0] adder_output;
     13
+
     13   wire [7:0] func_out;
     14   assign multiply_output = A * B;
+
     14
     15   assign adder_output = MAC ? multiply_output + Q : multiply_output;
+
    15   assign multiply_output = A * B;
     16
+
     16   assign adder_output = MAC ? multiply_output + Q : multiply_output;
     17   always @(posedge CLK or posedge RST)
+
     17
     18     if (RST)
+
     18   always @(posedge CLK or posedge RST)
     19       Q = 0;
+
     19     if (RST)
     20     else
+
     20       Q <= 0;
     21       Q = adder_output;
+
     21     else
     22
+
     22       Q <= adder_output;
     23 endmodule
+
     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
 
  </nowiki>
 
  </nowiki>
  
Line 236: Line 561:
  
 
  <nowiki>
 
  <nowiki>
-- Analyzing Verilog file 'prep5.v' (VERI-1482)
+
-- Analyzing Verilog file 'test.v' (VERI-1482)
prep5.v(14): INFO: multiply_output is assigned here as: multiply_output = (A * B)
+
test.v(15): 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)
+
test.v(16): 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 ;
+
test.v(20): INFO: 'Q' is assigned here as: Q <= 0 ;
prep5.v(21): INFO: Q is assigned here as: Q = adder_output ;
+
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))
 
  </nowiki>
 
  </nowiki>

Latest revision as of 22:42, 30 March 2021

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))