How to get linefile data of macros - Macro callback function

From Verific Design Automation FAQ
Revision as of 17:59, 26 January 2021 by Hoa (Talk | contribs)

Jump to: navigation, search

Note: for the applications below to work, the compile flag 'VERIFIC_LINEFILE_INCLUDES_COLUMNS' (util/VerificSystem.h) has to be enabled.

C++ application:

#include <iostream>
#include <sstream>

#include "veri_file.h"
#include "VeriTreeNode.h"

#include "Map.h"

using namespace std ;

#ifdef VERIFIC_NAMESPACE
using namespace Verific ;
#endif

class CppMacroCallBackHandler : public MacroCallBackHandler
{
public:
    CppMacroCallBackHandler() { }
    virtual ~CppMacroCallBackHandler() { }

private:
    // Prevent compiler from defining the following
    CppMacroCallBackHandler(const CppMacroCallBackHandler &) ;            // Purposely leave unimplemented
    CppMacroCallBackHandler& operator=(const CppMacroCallBackHandler &) ; // Purposely leave unimplemented

public:
    // This is called when an user defined macro is being defined using `define in active area:
    virtual void DefineMacro(const char *macro_name, const char *macro_body, const char *macro_args, const linefile_type lf)
    {
        cout << "A macro is being defined:\n" ;
        cout << "\tName: " << macro_name << endl ;
        if (macro_body) cout << "\tValue: " << macro_body << endl ;
        if (macro_args) cout << "\tArguments: " << macro_args << endl ;
        if (lf) cout << "\tLocation: " << PrintLocation(lf) << endl ;
    }

    // This is called when an user defined macro is being undefined using `undef in active area:
    virtual void UndefineMacro(const char *macro_name, const linefile_type lf)
    {
        cout << "A macro is being undefined:\n" ;
        cout << "\tName: " << macro_name << endl ;
        if (lf) cout << "\tLocation: " << PrintLocation(lf) << endl ;
    }

    // This is called when an user defined macro is being referenced using `MacroName or in `ifdef MacroName in active area:
    virtual void UserMacroRef(const char *macro_name, const char *macro_actuals, unsigned from_if_cond, unsigned from_active_area, const linefile_type lf)
    {
        cout << "A user macro is being referenced\n" ;
        cout << "\tName: " << macro_name << endl ;
        if (macro_actuals) cout << "\tActuals: " << macro_actuals << endl ;
        if (from_if_cond) cout << "\tFrom condition: " << from_if_cond << endl ;
        cout << "\tUsed in: " << ((from_active_area)?"Active":"Inactive") << " area\n" ;
        if (lf) cout << "\tLocation: " << PrintLocation(lf) << endl ;
    }

    // This is called when an pre-defined macros (`ifdef, `ifndef, `else, `elsif, `endif, `undef, `undefineall) are being processed.
    // This is called from both in active and inactive areas (`undef, `undefineall are skipped). Argument 'from_active_area' is set accordingly:
    virtual void PredefinedMacroRef(const char *macro_name, unsigned from_active_area, const linefile_type lf)
    {
        cout << "A predefined macro is being referenced\n" ;
        cout << "\tName: " << macro_name << endl ;
        cout << "\tUsed in: " << ((from_active_area)?"Active":"Inactive") << " area\n" ;
        if (lf) cout << "\tLocation: " << PrintLocation(lf) << endl ;
    }

private:
    string PrintLocation(const linefile_type lf)
    {
        ostringstream result("") ;

        if (lf) {
            result << lf->GetFileName() ;
            result << "[" ;
            result << lf->GetLeftLine() ;
            result << ":" ;
            result << lf->GetLeftCol() ;
            result << "] - " ;
            result << lf->GetFileName() ;
            result << "[" ;
            result << lf->GetRightLine() ;
            result << ":" ;
            result << lf->GetRightCol() ;
            result << "]" ;
        }

        return result.str() ;
    }
} ; // CppMacroCallBackHandler

int main(int argc, char **argv)
{
    CppMacroCallBackHandler mh ;
    veri_file::RegisterCallBackMacro(&mh) ;

    const char *file = (argc > 1) ? argv[1] : "test.v" ;
    if (!veri_file::Analyze(file)) return 1 ;

    return 0 ;
}
 

Perl script:

#!/usr/bin/perl -w

use strict ;
use warnings ;

use lib "../pm" ;
use Verific ;

{
    package PerlMacroCallBackHandler ;
        use base 'Verific::MacroCallBackHandler' ;
        # This is called when an user defined macro is being defined using `define in active area:
        sub DefineMacro
        {
            my ($class, $name, $body, $args, $lf) = @_ ;
            print "A macro is being defined:\n" ;
            print "\tName: $name\n" ;
            print "\tValue: $body\n" if ($body) ;
            print "\tArguments: $args\n" if ($args) ;
            print "\tLocation: " . PrintLocation($lf) . "\n" if ($lf) ;
        }

        # This is called when an user defined macro is being undefined using `undef in active area:
        sub UndefineMacro
        {
            my ($class, $name, $lf) = @_ ;
            print "A macro is being undefined:\n" ;
            print "\tName: $name\n" ;
            print "\tLocation: " . PrintLocation($lf) . "\n" if ($lf) ;
        }

        # This is called when an user defined macro is being referenced using `MacroName or in `ifdef MacroName in active area:
        # Argument $cond is set when it is used in condition of `ifdef or `endif or `elsif:
        sub UserMacroRef
        {
            my ($class, $name, $actual, $cond, $from_active_area, $lf) = @_ ;
            print "A user macro is being referenced\n" ;
            print "\tName: $name\n" ;
            print "\tActuals: $actual\n" if ($actual) ;
            print "\tFrom condition: $cond\n" if ($cond) ;
            print "\tUsed in: " . (($from_active_area)?"Active":"Inactive") . " area\n" ;
            print "\tLocation: " . PrintLocation($lf) . "\n" if ($lf) ;
        }

        # This is called when an pre-defined macros (`ifdef, `ifndef, `else, `elsif, `endif, `undef, `undefineall) are being processed.
        # This is called from both in active and inactive areas (`undef, `undefineall are skipped). Argument 'from_active_area' is set accordingly:
        sub PredefinedMacroRef
        {
            my ($class, $name, $from_active_area, $lf) = @_ ;
            print "A predefined macro is being referenced\n" ;
            print "\tName: $name\n" ;
            print "\tUsed in: " . (($from_active_area)?"Active":"Inactive") . " area\n" ;
            print "\tLocation: " . PrintLocation($lf) . "\n" if ($lf) ;
        }

        sub PrintLocation
        {
            my ($lf) = @_ ;
            if (!$lf) { return "NULL" ; }
            return $lf->GetFileName() . "[" . $lf->GetLeftLine() . ":" . $lf->GetLeftCol() . "] - " .
                   $lf->GetFileName() . "[" . $lf->GetRightLine() . ":" . $lf->GetRightCol() . "]" ;
        }
}

sub SetupCallBack
{
    my $pmcb = PerlMacroCallBackHandler->new() ;
    Verific::veri_file::RegisterCallBackMacro($pmcb) ;
}

sub ParseFile
{
    my ($file) = @_ ;
    Verific::veri_file::Analyze($file, $Verific::veri_file::SYSTEM_VERILOG) ;
}

my $file = "test.v" ;
if (scalar(@ARGV)) {
    $file = $ARGV[0] ;
}

SetupCallBack() ;
ParseFile($file) ;
 

Verilog testcase:

`define ABC

module test ;
`ifdef ABC 
    initial $display("ABC") ;
`elsif DEF
    initial $display("DEF") ;
`else 
    initial $display("!ABC") ;
`endif

`ifdef DEF 
    initial $display("DEF") ;
    `ifdef IGNORED_AREA
    `endif
    `ABC
    `DEF
`elsif ABC
    initial $display("ABC") ;
`else 
    initial $display("!DEF") ;
`endif
endmodule

`undef ABC
 

Output:

-- Analyzing Verilog file 'test.v' (VERI-1482)
A macro is being defined:
	Name: ABC
	Location: test.v[1:1] - test.v[2:1]
A predefined macro is being referenced
	Name: ifdef
	Used in: Active area
	Location: test.v[4:1] - test.v[4:7]
A user macro is being referenced
	Name: ABC
	From condition: 1
	Used in: Active area
	Location: test.v[4:8] - test.v[4:11]
A predefined macro is being referenced
	Name: elsif
	Used in: Active area
	Location: test.v[6:1] - test.v[6:7]
A user macro is being referenced
	Name: DEF
	From condition: 1
	Used in: Inactive area
	Location: test.v[6:8] - test.v[6:11]
A predefined macro is being referenced
	Name: else
	Used in: Inactive area
	Location: test.v[8:1] - test.v[8:6]
A predefined macro is being referenced
	Name: endif
	Used in: Inactive area
	Location: test.v[10:1] - test.v[10:7]
A predefined macro is being referenced
	Name: ifdef
	Used in: Active area
	Location: test.v[12:1] - test.v[12:7]
A user macro is being referenced
	Name: DEF
	From condition: 1
	Used in: Active area
	Location: test.v[12:8] - test.v[12:11]
A predefined macro is being referenced
	Name: ifdef
	Used in: Inactive area
	Location: test.v[14:5] - test.v[14:11]
A user macro is being referenced
	Name: IGNORED_AREA
	From condition: 1
	Used in: Inactive area
	Location: test.v[14:12] - test.v[14:24]
A predefined macro is being referenced
	Name: endif
	Used in: Inactive area
	Location: test.v[15:5] - test.v[15:11]
A user macro is being referenced
	Name: ABC
	Used in: Inactive area
	Location: test.v[16:5] - test.v[16:9]
A user macro is being referenced
	Name: DEF
	Used in: Inactive area
	Location: test.v[17:5] - test.v[17:9]
A predefined macro is being referenced
	Name: elsif
	Used in: Inactive area
	Location: test.v[18:1] - test.v[18:7]
A user macro is being referenced
	Name: ABC
	From condition: 1
	Used in: Active area
	Location: test.v[18:8] - test.v[18:11]
A predefined macro is being referenced
	Name: else
	Used in: Active area
	Location: test.v[20:1] - test.v[20:6]
A predefined macro is being referenced
	Name: endif
	Used in: Inactive area
	Location: test.v[22:1] - test.v[22:7]
A predefined macro is being referenced
	Name: undef
	Used in: Active area
	Location: test.v[25:1] - test.v[25:7]
A user macro is being referenced
	Name: ABC
	Used in: Active area
	Location: test.v[25:8] - test.v[25:11]
A macro is being undefined:
	Name: ABC
	Location: test.v[25:8] - test.v[25:11]