Difference between revisions of "Where in RTL does it get assigned?"
From Verific Design Automation FAQ
(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! | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
Line 194: | Line 198: | ||
int main(void) | int main(void) | ||
{ | { | ||
− | if (!veri_file::Analyze(" | + | 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 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 | ||
</nowiki> | </nowiki> | ||
Line 236: | Line 561: | ||
<nowiki> | <nowiki> | ||
− | -- Analyzing Verilog file ' | + | -- 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)) | ||
</nowiki> | </nowiki> |
Latest revision as of 21: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))