Where in RTL does it get assigned?

From Verific Design Automation FAQ
Revision as of 14:06, 23 March 2021 by Hoa (Talk | contribs) (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...")

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

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 ;