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]