How to get linefile data of macros - Macro callback function
From Verific Design Automation FAQ
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) {
#ifdef VERIFIC_LINEFILE_INCLUDES_COLUMNS
result << lf->GetFileName() ;
result << "[" ;
result << lf->GetLeftLine() ;
result << ":" ;
result << lf->GetLeftCol() ;
result << "] - " ;
result << lf->GetFileName() ;
result << "[" ;
result << lf->GetRightLine() ;
result << ":" ;
result << lf->GetRightCol() ;
result << "]" ;
#else
result << LineFile::GetFileName(lf) ;
result << "[" ;
result << LineFile::GetLineNo(lf) ;
result << "]" ;
#endif
}
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) ;
Python script:
cat test.py
#!/usr/bin/python
import sys
sys.path.append('../py')
import Verific
class my_macro_cb (Verific.MacroCallBackHandler) :
def __init__ (self):
Verific.MacroCallBackHandler.__init__ (self)
def DefineMacro (self, macro_name, macro_body, macro_args, lf) :
if (macro_body == None) :
macro_body = ""
if (macro_args) :
print("=====> `define %s(%s) %s" % (macro_name, macro_args, macro_body))
else :
print("=====> `define %s %s" % (macro_name, macro_body))
def UndefineMacro (self, macro_name, lf) :
print("=====> `undefine %s" % macro_name)
def UserMacroRef (self, macro_name, macro_actuals, from_if_cond, from_active_area, lf) :
if (macro_actuals) :
print("=====> `%s(%s)" % (macro_name, macro_actuals))
else :
print("=====> `%s" % macro_name)
def PredefinedMacroRef (self, macro_name, from_active_area, lf) :
print("=====> `%s (predefined macro)" % macro_name)
# END of my_macro_cb
veri_parser = Verific.veri_file()
cb = my_macro_cb()
veri_parser.RegisterCallBackMacro(cb)
Verific.RuntimeFlags_SetVar("veri_include_ansi_file_search", 1)
Verific.RuntimeFlags_SetVar("veri_improve_include_dir_processing_runtime_for_network_file_system", 1)
file_names_ptr = Verific.PythonProcessFFile("filelist.f", veri_parser.F_FILE_NONE, veri_parser.SYSTEM_VERILOG)
if (file_names_ptr) :
if (veri_parser.AnalyzeMultipleFiles(file_names_ptr, veri_parser.SYSTEM_VERILOG) == 0) :
print("Failed to analyze files")
exit (0)
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]