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