/vrq-1.0.88/src/main.cc
C++ | 1464 lines | 1037 code | 87 blank | 340 comment | 268 complexity | 44fe90e53ee1fc19d5c8c0b6b44be4e6 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0
- /*****************************************************************************
- * Copyright (C) 1997-2007, Mark Hummel
- * This file is part of Vrq.
- *
- * Vrq is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * Vrq is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- *****************************************************************************
- */
- /******************************************************************************
- *
- *
- * main.cpp
- * - simulator startup code
- *
- *
- ******************************************************************************
- */
- /**
- * \mainpage
- * VRQ is modular verilog parser that supports plugin tools to process
- * verilog. Plugin tools are created as independent DLLs. The tools to
- * be invoked are specified on the command line. Multiple tools may be
- * invoke in a pipeline fashion within a single execution of vrq. A few
- * plugin tools are natively compiled into vrq, others are supplied as
- * separate executables. Vrq is pretty close to fully compliant with
- * the verilog 2005 specification, however not all tools support all
- * constructs.
- *
- * \section history History
- * VRQ was written over 10 years ago as part of my design and verification
- * consulting business. Over the years its been generalized to be a generic
- * front end parser with plugin backend customizable tools. I've choosen to
- * release it as Open Source Software to others may benefit from it as well.
- * It has been used in multiple startups and Fortune 500 companies to develop
- * ASICs and full custom components. In particular the \ref xprop_plugin is
- * one of it's most unique features as when it is used properly it can greatly
- * reduce the need for gate level simulation.
- *
- * \section further_info Further Info
- * - \ref quick_start
- * - \ref plugin_list
- * - \ref faq
- * - \ref manpage
- * - \ref plugin_info
- *
- * \page manpage Man Page
- * \htmlinclude vrq.1.html
- *
- * \page faq Frequently Asked Questions
- * \htmlinclude faq.html
- *
- * \page plugin_list Plugin List
- * - \ref dump_plugin
- * - \ref xprop_plugin
- * - sim
- * - builder
- * - coverage
- * - stats
- * - flatten
- * - \ref filter_plugin
- *
- * \page quick_start Quick Start
- * \section switches Switches
- * The parser has a number of switches that control the parsing of files.
- * Below is detail on a subset of the switches. For a complete list see the
- * \ref manpage .
- * - -y <directory> This switch may be used to specify a verilog library
- * search path for tools that require modules to be resolved.
- * - -v <lib_filename> This switch may be used to specify a verilog library
- * file for tools that require modules to be resolved.
- * - +libext+<extension> This switch may be used to specify the library
- * file suffix (used with the -y switch). Multiple extensions may be
- * specified by appending more extensions: +libext+<ext1>+<ext2>+...
- * - -infervectors This switch will allow the parser to infer register
- * definitions and vector wire definitions.
- * - -macrocheck This switch will cause the use of undefined macros to
- * be flagged as errors.
- * - -keeptickdefines This switch makes a best effort attempt to keep
- * tick defines and `include statements in the code (EXPERIMENTAL). `include
- * statements are keep if the include file is composed solely of pragmas,
- * comments and `define statements. `variables are evaluated if their
- * definition is in the same preprocessor zone as their instantiation.
- * Command line switches are in zone by themselves. Each compilation unit
- * (e.g. verilog inpug file) starts a new zone. Included files are part of the
- * zone of the including file. -passthru regions start a new zone. `ifdef
- * and `ifndef regions start a new zone if they are dependent upon undefined
- * preprocessor variables or are dependent upon preprocessor variable
- * defined in another zone. One of the side effects of enabling this
- * switch is that `define and `include statements can only occur on statement
- * boundries in the source code, otherwise a parsing error will result.
- * - +incdir+<directory> This switch will cause 'directory' to be searched
- * to resolve `include preprocessor directives. Multiple paths may be
- * specified by either using +incdir+ switches or by specifing multiple i
- * directories: +incdir+<dir1>+<dir2>+....
- * - -allowmissingincludes This switch will ignore `include preprocessor
- * directives that cannot be resolved.
- * - +define+<name>=<val> This switch specifies `define variables on
- * the command line.
- * - +<name>+<val> This switch is used to specify plusargs for tools
- * that use them.
- * - -pragma <regexp> This switch is used to identify classes of comments
- * as pragmas. Vrq will ensure that pragmas are not move relative to the
- * code they are embedded in. Note a side effect of using pragmas is that
- * vrq only allows pragmas in very specific locations in the code. Vrq
- * uses regcomp to process the match. Please see the 'regcomp' man page
- * for the format of 'regexp'. Multiple -pragma switch may appear on the
- * command line. If no -pragma switch is specified, vrq will make all i
- * // synopsys ..... and comments as pragmas.
- * - -passthru <name> This switch can be used to create a label to identify
- * regions of the source code that vrq should ignore and pass though
- * verbatim. These regions of code will be treated as comments and
- * `define substitution will be performed. To use the label use
- * `ifdef/`endif and `ifndef/`endif pairs to flags the regions as
- * shown below:
- * \code
- * `ifdef label
- * put code here that you want to pass through
- * `endif
- *
- * or
- *
- * `ifndef
- * put code here that you want to pass through
- * `endif
- * \endcode
- *
- * \section tool_pipelines Tool Pipelines
- * Vrq parses each file creating an Abstract Syntax Tree (AST) for each file.
- * This vector of AST's is passed on through a filter pipeline. Each filter
- * in the pipeline is specified using the -tool <toolname> switch. A filter
- * always takes a vector of AST's as input and optionally outputs a vector
- * of AST's. If a pipeline is specified where the final filter produces
- * AST's, vrq will automatically append the 'dump' tool to the end of the
- * pipeline.
- *
- * For instance if the following switches are used; -tool filter1 -tool filter2
- * is specified, vrq will create the following pipeline:
- * Parser -> filter1 -> filter2 -> dump
- *
- * Some tools are compiled in, others come with the vrq distribution and
- * are compiled as DLLs placed in the plugin dir specified at vrq install
- * time. The search path for plugins may be augmented by using the PLUGIN_DIR
- * environment variable. ie PLUGIN_DIR=path1:path2:path3. Third parties can
- * create their own filters using the vrq API. If these plugins are placed
- * in the plugin search path, vrq will automatically recognize them.
- *
- * Each AST is tagged by the parser with the input file name it was
- * derived from. Tools may modify these names and trees. Tools may also
- * expand or contract the number of AST in the vector.
- */
- #include <config.h>
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #include <set>
- #include <vector>
- #include <list>
- #include <map>
- //#include <dlfcn.h>
- #include <sys/types.h>
- #include <dirent.h>
- #include "glue.h"
- #include "ltdl.h"
- #include "cobstack.h"
- #include "csymbol.h"
- #include "cvector.h"
- #include "cnode.h"
- #include "lex.h"
- #include "main.h"
- #include "csymtab.h"
- #include "cmacro.h"
- #include "cmodule.h"
- #include "cinstance.h"
- #include "systask.h"
- #include "build.h"
- #ifdef BUILTIN_SIM_PLUGIN
- #include "../plugin/sim/csim.h"
- #endif
- /*
- * add tool includes here
- */
- #include "cxprop.h"
- #include "cdumpverilog.h"
- map<string,CBackend*> tools;
- Message* mCRMOD;
- CObstack thePermStack( "permStack" );
- CObstack* permStack = &thePermStack;
- CObstack theUnitStack( "unitStack" );
- CObstack* unitStack = &theUnitStack;
- CObstack thePluginStack( "pluginStack" );
- CObstack* pluginStack = &thePluginStack;
- CObstack theTokenStack( "tokenStack" );
- CObstack* tokenStack = &theTokenStack;
- /*
- * set default logfile to stdout
- */
- FILE* logfile = stdout;
- /*
- * this must be instantiated here so it will
- * have a valid memmgr (permMgr).
- */
- list<CObstack*> CNode::stackList;
- /*
- * contains current definitions for macros
- * this namespace is global
- */
- CSymtab<CMacro> macroSymtab;
- /*
- * contains the definitions for
- * instances, functions, named blocks, nets
- * and registers for the current compilation unit.
- */
- CSymtab<CDecl> cuSymtab;
- /*
- * top level definitions for resolving all
- * non-nested module, macromodule, primitive,
- * program and interface identifiers.
- */
- CSymtab<CDecl> definitionSymtab = cuSymtab;
- /*
- * List of specified tools to run
- */
- list<CBackend*> enabledTools;
- /*
- * list of pragma templates
- */
- list<string> pragmas;
- set<string> pragmaTickDefines;
- /*
- * list of plugin directorys
- */
- list<string> pluginPaths;
- int totalMem = 0;
- const CSymbol** fileList = NULL; // list of files to compile
- const CSymbol** libSearchList = NULL; // list of paths to search for libraries
- const CSymbol** libFileSearchList = NULL; // list of library files to search
- const CSymbol** incSearchList = NULL; // list of paths to search for includes
- const CSymbol** libExtList = NULL; // list of library extentions
- static char whiteSpace[] = " \t\f\n\r";
- INT32 argNestLevel; // all argument parsing to nest
- vector<const CSymbol*> aFileList;
- vector<const CSymbol*> aLibSearchList;
- vector<const CSymbol*> aLibFileSearchList;
- vector<const CSymbol*> aIncSearchList;
- vector<const CSymbol*> aLibExtList;
- CNode* codeList = NULL;
- CSymtab<CDecl> portSymtab;
- CSymtab<CDecl> frefSymtab;
- int errorCount = 0;
- int warningCount = 0;
- int dumpFlag = FALSE;
- int debugFlag = FALSE;
- int quietFlag = FALSE;
- int inferVectors = FALSE;
- int macrocheck = FALSE;
- DelayMode_t delayMode = eTYP_DELAY;
- const char* outputPath = NULL;
- const char* outputDirectory = NULL;
- vector<char*> plusArgs;
- extern int modulesDirectlyDefined;
- extern int modulesIncluded;
- int ignoreVrqComments = 0;
- int verboseFlag = FALSE;
- int svEnable = FALSE;
- extern int keepMacros;
- extern int keepMacroDefinitions;
- /*
- * error messages
- */
- static Message* mILLPA = Message::RegisterWarning( NULL,
- Message::eERROR, "ILLPA",
- "%s is an illegal command line plusarg",
- "<plusarg>", 0 );
- static Message* mILLWS = Message::RegisterWarning( NULL,
- Message::eERROR, "ILLWS",
- "%s is an illegal warning specification",
- "<warning switch>", 0 );
- static Message* mILLSW = Message::RegisterWarning( NULL,
- Message::eERROR, "ILLSW",
- "%s is an illegal command line switch",
- "<switch>", 0 );
- static Message* mINAST = Message::RegisterWarning( NULL,
- Message::eERROR, "INAST",
- "%s is not a supported tool",
- "<tool>", 0 );
- CDumpVerilog* dumpVerilog;
- #ifdef BUILTIN_SIM_PLUGIN
- CSim* sim;
- #endif
- void ParseArguments( int argc, const char** argv );
- #define VRQ "Vrq"
- char copyright[] = "Copyright (C) 1997-2009 Mark Hummel\n\n"
- "Vrq comes with ABSOLUTELY NO WARRANTY; This is free\n"
- "software, and you are welcome to redistribute it under the\n"
- "terms of the GNU General Public License as published by\n"
- "the Free Software Foundation; either version 2 of the License,\n"
- "or (at your option) any later version. "
- "\n\n";
- /*************************************************
- library interface routines
- *************************************************/
- void shell_assert( const char* filename, int linenumber ) {
- fatal( NULL, "Assertion Failure -> %s[%d]\n", filename, linenumber );
- }
- void shell_xfree( void* p, int s ){
- free( p );
- totalMem -= s;
- }
- void* shell_xmalloc( int s ) {
- totalMem += s;
- return malloc(s);
- }
- /*************************************************
- PrintUsage
- - print command line help
- *************************************************/
- void PrintUsage( void )
- {
- INT32 i;
- printf( "\n" );
- printf( "'Vrq' is a framework for creating verilog based tools.\n\n" );
- printf( "Usage: vrq [options] <file1> [<file2>...]\n\n" );
- printf( "Options:\n" );
- printf( " --version Print version\n" );
- printf( " --help This message\n" );
- printf( " --bindir Binary install path\n");
- printf( " --libdir Library install path\n");
- printf( " --pkglibdir Plugin install path\n");
- printf( " --includedir Include install path\n");
- printf( " --cflags Compiler flags used\n");
- printf( " --ldflags Linker flags used\n");
- printf( " --libs Libraries used\n");
- printf( " -V Verbose\n" );
- printf( " -y <directory> Search directory for module definitions\n" );
- printf( " -f <filename> Read options from <filename>\n" );
- printf( " -v <lib_filename> Search file for module definitions\n" );
- printf( " -l <filename> Set log file to <filename>\n" );
- printf( " -w <message>=<policy> Set policy for warning <message> to <policy>; ignore, warning, error, info\n" );
- printf( " -w all=<policy> Set policy for all warnings to <policy>; ignore, warning, error, info\n" );
- printf( " -wl List all warning messages\n" );
- printf( " +libext+<extension> Specify library suffix to <extension>\n" );
- printf( " -sv Enable System Verilog support\n" );
- printf( " -dump Dump internal tree\n" );
- printf( " -debug Print debug/statistics info\n" );
- printf( " -quiet Print minimal runtime info\n" );
- printf( " -infervectors Infer reg and wire vectors\n" );
- printf( " -keeptickdefines Best effort attempt to keep tick defines and `include statements in code (EXPERIMENTAL)\n" );
- printf( " -macrocheck Do not allow undefined macros\n" );
- printf( " -o <filename> Specify output file\n" );
- printf( " -dir <directory> Specify output directory\n" );
- printf( " -pragma <regexp> Extended regular expression template for pragma comments\n" );
- printf( " -passthru <name> Pass through ifdef blocks with label\n" );
- printf( " +incdir+<directory> Specify include search path\n" );
- printf( " +define+<name>=<value> Define `define\n" );
- printf( " +<name>+<value> Define plusargs\n" );
- map<string,CBackend*>::iterator ptr;
- for( ptr = tools.begin(); ptr != tools.end(); ++ptr ) {
- if( ptr->second->HideTool() ) {
- continue;
- }
- printf( " -tool %-20s %s\n",
- (*ptr).second->GetToolName(),
- (*ptr).second->GetToolDescription() );
- }
- for( ptr = tools.begin(); ptr != tools.end(); ++ptr ) {
- if( ptr->second->HideTool() ) {
- continue;
- }
- list<string>& switches = ptr->second->GetSwitches();
- if( switches.size() == 0 ) {
- continue;
- }
- printf( "\n* '%s' Options\n", (*ptr).second->GetToolName() );
- list<string>::iterator swPtr;
- for( swPtr = switches.begin(); swPtr != switches.end(); ++swPtr ) {
- printf( " %-26s %s\n",
- swPtr->c_str(),
- (*ptr).second->GetSwitchDescription(swPtr->c_str()) );
- }
- }
- printf( "\n" );
- printf( "Report bugs at <http://sourceforge.net/projects/vrq>\n" );
- }
- /*************************************************
- VrqVersionString
- ************************************************/
- static const char* vrqVersion = VERSION;
- const char* VrqVersionString()
- {
- return vrqVersion;
- }
- /*************************************************
- GetPluginPaths
- - retrieve list of plugin location paths
- *************************************************/
- void GetPluginPaths( list<string>& paths )
- {
- paths = pluginPaths;
- }
- /*************************************************
- GetPlusArgs
- - retrieve plus arg list from command line
- args matching prefix
- *************************************************/
- void GetPlusArgs( const char* prefix, list<string>& args )
- {
- args.erase( args.begin(), args.end() );
- vector<char*>::iterator ptr;
- for( ptr = plusArgs.begin(); ptr != plusArgs.end(); ++ptr ) {
- int len = strlen( prefix );
- if( !strncmp( *ptr, prefix, len ) ) {
- args.push_back(*ptr+len);
- }
- }
- }
- /*************************************************
- GetPlusArg
- - retrieve plus arg from command line matching
- prefix
- *************************************************/
- char* GetPlusArg( const char* prefix )
- {
- vector<char*>::iterator ptr;
- for( ptr = plusArgs.begin(); ptr != plusArgs.end(); ++ptr ) {
- int len = strlen( prefix );
- if( !strncmp( *ptr, prefix, len ) ) {
- return (*ptr+len);
- }
- }
- return NULL;
- }
- /*************************************************
- AddPlusArg
- - add plus arg to list
- *************************************************/
- void AddPlusArg( const char* s )
- {
- plusArgs.push_back(strdup(s+1));
- }
- /*************************************************
- PlusArgMatch
- - return TRUE if plus arg matches string
- *************************************************/
- int PlusArgMatch( const char* s1, const char* s2 )
- {
- int l1 = strlen( s1 );
- int l2 = strlen( s2 );
- const char* p1 = strpbrk( s1, "+=" );
- if( p1 ) {
- l1 = p1 - s1;
- }
- const char* p2 = strpbrk( s2, "+=" );
- if( p2 ) {
- l2 = p2 - s2;
- }
- if( l1 == l2 && !strncmp(s1,s2,l1) ) {
- return TRUE;
- }
- return FALSE;
- }
- /*************************************************
- ValidatePlusArgs
- - validate all plus args
- *************************************************/
- void ValidatePlusArgs()
- {
- vector<char*>::iterator paPtr;
- for( paPtr = plusArgs.begin(); paPtr != plusArgs.end(); ++paPtr ) {
- list<CBackend*>::iterator ptr;
- if( PlusArgMatch( *paPtr, "define" ) ) {
- goto FOUND;
- }
- if( PlusArgMatch( *paPtr, "incdir" ) ) {
- goto FOUND;
- }
- if( PlusArgMatch( *paPtr, "libext" ) ) {
- goto FOUND;
- }
- if( PlusArgMatch( *paPtr, "xprop-allow-casex" ) ) {
- goto FOUND;
- }
- for( list<string>::iterator sPtr = dumpVerilog->GetSwitches().begin();
- sPtr != dumpVerilog->GetSwitches().end(); ++sPtr ) {
- if( PlusArgMatch( *paPtr, &sPtr->c_str()[1] ) ) {
- goto FOUND;
- }
- }
- for( ptr = enabledTools.begin(); ptr != enabledTools.end(); ++ptr ) {
- if( (*ptr)->AcceptAllPlusArgs() ) {
- goto FOUND;
- }
- list<string>::iterator sPtr;
- for( sPtr = (*ptr)->GetSwitches().begin();
- sPtr != (*ptr)->GetSwitches().end(); ++sPtr ) {
- if( PlusArgMatch( *paPtr, &sPtr->c_str()[1] ) ) {
- goto FOUND;
- }
- }
- }
- message( NULL, mILLPA, *paPtr );
- if( errorCount ) {
- PrintUsage();
- exit(1);
- }
- FOUND:
- continue;
- }
- }
- /*************************************************
- DumpWarningList
- - output a list of all possible warnings
- *************************************************/
- void DumpWarningList()
- {
- list<Message*>& warnings = Message::MessageList();
- list<Message*>::iterator ptr;
- printf( "List of warning messages:\n" );
- for( ptr = warnings.begin(); ptr != warnings.end(); ++ptr ) {
- Message* message = *ptr;
- const char* policy;
- switch( message->Action() ) {
- case Message::eINFO:
- policy = "info";
- break;
- case Message::eIGNORE:
- policy = "ignore";
- break;
- case Message::eERROR:
- policy = "error";
- break;
- case Message::eWARNING:
- policy = "warning";
- break;
- default:
- MASSERT( FALSE );
- }
- printf( "%s[%s]: %s\n", message->Abbreviation(),
- policy, message->HelpText() );
- }
- exit(0);
- }
- /*************************************************
- ParseWarningSwitch
- - handle switch to modify warning policy
- *************************************************/
- void ParseWarningSwitch( const char* s )
- {
- string abbrev = s;
- string policy;
- const char* ptr;
- ptr = strchr( s, '=' );
- if( ptr ) {
- policy = ptr+1;
- abbrev = abbrev.substr(0, ptr-s);
- Message::Action_t action;
- if( !policy.compare( "ignore" ) ) {
- action = Message::eIGNORE;
- } else if( !policy.compare( "info" ) ) {
- action = Message::eINFO;
- } else if( !policy.compare( "error" ) ) {
- action = Message::eERROR;
- } else if( !policy.compare( "warning" ) ) {
- action = Message::eWARNING;
- } else {
- error( (Coord_t*)NULL, "illegal warning policy '%s'", policy.c_str() );
- goto ERROR;
- }
- if( !abbrev.compare( "all" ) ) {
- list<Message*>::iterator ptr;
- for( ptr = Message::MessageList().begin();
- ptr != Message::MessageList().end(); ++ ptr ) {
- if( (*ptr)->Locked() ) {
- continue;
- }
- (*ptr)->Action( action );
- }
- return;
- }
- Message* message = Message::Find( abbrev.c_str() );
- if( !message ) {
- error( (Coord_t*)NULL, "unknown warning message '%s'",
- abbrev.c_str() );
- goto ERROR;
- }
- if( message->Locked() ) {
- error( (Coord_t*)NULL, "message policy for '%s' cannot be changed",
- abbrev.c_str() );
- goto ERROR;
- }
- message->Action( action );
- return;
- }
- message( NULL, mILLWS, s );
- if( !errorCount ) {
- return;
- }
- PrintUsage();
- ERROR:
- exit(1);
- }
- /*************************************************
- ReadArgumentFile
- - read command line argument file
- *************************************************/
- void ReadArgumentFile( const char* filename )
- {
- int newArgc;
- const char** newArgv;
- const CSymbol** newArgvSymbol;
- vector<const CSymbol*> argList;
- FILE* fin = fopen( filename, "r" );
- if( fin == NULL ) {
- error( (Coord_t*)NULL, "Couldn't open file '%s'", filename );
- exit( 2 );
- }
- int strip = TRUE;
- newArgc = 1;
- argList.push_back( CSymbol::Lookup( "dummy" ) );
- while( TRUE ) {
- int c = fgetc( fin );
- int marker = (strchr( whiteSpace, c ) || c == EOF);
- if( c == '/' ) {
- int c1 = fgetc( fin );
- if( c1 == '/' ) {
- do {
- c1 = fgetc( fin );
- } while( c1 != EOF && c1 != '\n' && c1 != '\r' );
- marker = TRUE;
- } else if( c1 == '*' ) {
- while( 1 ) {
- c1 = fgetc( fin );
- if( c1 == EOF ) {
- break;
- }
- if( c1 != '*' ) {
- continue;
- }
- c1 = fgetc( fin );
- if( c1 == EOF ) {
- break;
- }
- if( c1 != '/' ) {
- continue;
- }
- break;
- }
- marker = TRUE;
- } else {
- ungetc( c1, fin );
- }
- }
- int done = (c == EOF);
- if( marker || done ) {
- if( strip ) {
- if( done ) {
- break;
- } else {
- continue;
- }
- }
- c = 0;
- strip = TRUE;
- permStack->Grow( &c, 1 );
- const CSymbol* sym = CSymbol::Lookup( (char*) permStack->Finish() );
- argList.push_back( sym );
- newArgc++;
- } else {
- strip = FALSE;
- permStack->Grow( &c, 1 );
- }
- if( done ) {
- break;
- }
- }
- newArgvSymbol = Finalize( permStack, argList );
- newArgv = (const char**)newArgvSymbol;
- fclose( fin );
- for( int j = 0; newArgvSymbol[j]; j++ ) {
- newArgv[j] = newArgvSymbol[j]->GetName();
- }
- ParseArguments( newArgc, newArgv );
- }
- /*************************************************
- ParseArguments
- - parse command line arguments
- *************************************************/
- void ParseArguments( int argc, const char** argv )
- {
- INT32 i;
- INT32 j;
- int c;
- FILE* fin;
- argNestLevel++;
- for( i = 1; i < argc; i++ ) {
- switch( argv[i][0] ) {
- case '-':
- if( !strcmp( &argv[i][1], "dump" ) ) {
- dumpFlag = TRUE;
- } else if( !strcmp( &argv[i][1], "sv" ) ) {
- svEnable = TRUE;
- } else if( !strcmp( &argv[i][1], "-version" ) ) {
- printf("%s %s, \n\n", VRQ, VERSION );
- printf( copyright );
- printf( "\nWritten by Mark Hummel\n" );
- exit(0);
- } else if( !strcmp( &argv[i][1], "-help" ) ) {
- PrintUsage();
- exit(0);
- } else if (!strcmp( &argv[i][1], "-bindir" ) ) {
- printf( "%s\n", BINDIR );
- exit(0);
- } else if (!strcmp( &argv[i][1], "-libdir" ) ) {
- printf( "%s\n", LIBDIR );
- exit(0);
- } else if (!strcmp( &argv[i][1], "-includedir" ) ) {
- printf( "%s\n", INCLUDEDIR );
- exit(0);
- } else if (!strcmp( &argv[i][1], "-pkglibdir" ) ) {
- printf( "%s\n", PKGLIBDIR );
- exit(0);
- } else if (!strcmp( &argv[i][1], "-cflags" ) ) {
- printf( "%s\n", CFLAGS );
- exit(0);
- } else if (!strcmp( &argv[i][1], "-ldflags" ) ) {
- printf( "%s\n", LDFLAGS );
- exit(0);
- } else if (!strcmp( &argv[i][1], "-libs" ) ) {
- printf( "%s\n", LIBS );
- exit(0);
- } else if( !strcmp( &argv[i][1], "macrocheck" ) ) {
- macrocheck = TRUE;
- } else if( !strcmp( &argv[i][1], "infervectors" ) ) {
- inferVectors = TRUE;
- } else if( !strcmp( &argv[i][1], "keeptickdefines" ) ) {
- keepMacros = TRUE;
- keepMacroDefinitions = TRUE;
- } else if( !strcmp( &argv[i][1], "debug" ) ) {
- debugFlag = TRUE;
- } else if( !strcmp( &argv[i][1], "quiet" ) ) {
- quietFlag = TRUE;
- } else if( !strcmp( &argv[i][1], "V" ) ) {
- verboseFlag = TRUE;
- } else if( !strcmp( &argv[i][1], "y" ) ) {
- aLibSearchList.push_back( CSymbol::Lookup( argv[i+1] ) );
- i++;
- } else if( !strcmp( &argv[i][1], "f" ) ) {
- ReadArgumentFile( argv[i+1] );
- i++;
- } else if( !strcmp( &argv[i][1], "w" ) ) {
- ParseWarningSwitch( argv[i+1] );
- i++;
- } else if( !strcmp( &argv[i][1], "wl" ) ) {
- DumpWarningList();
- } else if( !strcmp( &argv[i][1], "v" ) ) {
- aLibFileSearchList.push_back( CSymbol::Lookup( argv[i+1] ) );
- i++;
- } else if( !strcmp( &argv[i][1], "o" ) ) {
- outputPath = argv[i+1];
- i++;
- } else if( !strcmp( &argv[i][1], "dir" ) ) {
- outputDirectory = argv[i+1];
- i++;
- } else if( !strcmp( &argv[i][1], "pragma" ) ) {
- pragmas.push_back( argv[i+1] );
- i++;
- } else if( !strcmp( &argv[i][1], "passthru" ) ) {
- pragmaTickDefines.insert( argv[i+1] );
- i++;
- } else if( !strcmp( &argv[i][1],
- "allowmissingincludes" ) ) {
- ParseWarningSwitch( "vrq-COIDF=ignore" );
- warning( (Coord_t*)NULL, "switch '%s' is depreciated and will be removed in a future release", argv[i] );
- } else if( !strcmp( &argv[i][1], "l" ) ) {
- logfile = fopen( argv[i+1], "w" );
- if( logfile == NULL ) {
- logfile = stdout;
- error( (Coord_t*)NULL, "Couldn't open logfile '%s'", argv[i+1] );
- }
- i++;
- } else if( !strcmp( &argv[i][1], "tool" ) ) {
- INT32 j;
- map<string,CBackend*>::iterator ptr;
- for( ptr = tools.begin(); ptr != tools.end(); ++ptr ) {
- if( !strcmp( (*ptr).second->GetToolName(), argv[i+1] ) ) {
- enabledTools.push_back( (*ptr).second );
- i++;
- break;
- }
- }
- if( ptr == tools.end() ) {
- message( NULL, mINAST, argv[i+1] );
- if( errorCount ) {
- PrintUsage();
- exit(1);
- }
- }
-
- } else {
- message( NULL, mILLSW, argv[i] );
- if( errorCount ) {
- PrintUsage();
- exit(1);
- }
- }
- break;
- case '+':
- AddPlusArg( argv[i] );
- if( !strncmp( argv[i], "+incdir", 7 ) ) {
- const char* ptr = &argv[i][7];
- const char* ptr1;
- char c;
- while( ptr && *ptr == '+' ) {
- ptr++;
- ptr1 = strchr( ptr, '+' );
- if( ptr1 == NULL ) {
- ptr1 = ptr + strlen(ptr);
- if( ptr1 == ptr ) {
- break;
- }
- }
- permStack->Grow( ptr, ptr1-ptr );
- c = 0;
- permStack->Grow( &c, 1 );
- const CSymbol* sym = CSymbol::Lookup( (char*)permStack->Finish() );
- aIncSearchList.push_back( sym );
- ptr = ptr1;
- }
- }
- if( !strncmp( argv[i], "+define", 7 ) ) {
- const char* ptr = &argv[i][7];
- const char* ptr1;
- const char* ptr2;
- const char* ptr3;
- char* key;
- char* value;
- while( ptr && *ptr == '+' ) {
- ptr++;
- ptr3 = strchr( ptr, '+' );
- if( ptr3 == NULL ) {
- ptr3 = ptr + strlen(ptr);
- if( ptr3 == ptr ) {
- break;
- }
- }
- ptr1 = strchr( ptr, '=' );
- if( !ptr1 ) {
- ptr1 = ptr3;
- ptr2 = ptr3;
- } else if( ptr1 > ptr3 ) {
- ptr1 = ptr3;
- ptr2 = ptr3;
- } else {
- ptr2 = ptr1+1;
- }
- permStack->Grow( ptr, ptr1-ptr );
- c = 0;
- permStack->Grow( &c, 1 );
- key = (char*)permStack->Finish();
- permStack->Grow( ptr2, ptr3-ptr2 );
- c = 0;
- permStack->Grow( &c, 1 );
- value = (char*)permStack->Finish();
- CMacro* macro;
- CSymbol* symbol;
- macro = CMacro::LookupMacro( key );
- if( macro == NULL ) {
- symbol = CSymbol::Lookup( key );
- Coord_t loc = { 0, "" };
- macro = new(permStack) CMacro( symbol, &loc );
- } else {
- Coord_t loc = { 0, "" };
- macro->SetCoord( &loc );
- }
- macro->SetComplex(FALSE);
- macro->SetDefined(TRUE);
- macro->SetBody( value );
- macro->SetZone( 0 );
- ptr = ptr3;
- }
- }
- if( !strncmp( argv[i], "+libext", 7 ) ) {
- const char* ptr = &argv[i][7];
- const char* ptr1;
- char c;
- while( ptr && *ptr == '+' ) {
- ptr++;
- ptr1 = strchr( ptr, '+' );
- if( ptr1 == NULL ) {
- ptr1 = ptr + strlen(ptr);
- if( ptr1 == ptr ) {
- break;
- }
- }
- permStack->Grow( ptr, ptr1-ptr );
- c = 0;
- permStack->Grow( &c, 1 );
- const CSymbol* sym = CSymbol::Lookup( (char*) permStack->Finish() );
- aLibExtList.push_back( sym );
- ptr = ptr1;
- }
- }
- if( !strncmp( argv[i], "+xprop-allow-casex", 18 ) ) {
- ParseWarningSwitch( "xprop-CCBMS=ignore" );
- }
- break;
- default:
- aFileList.push_back( CSymbol::Lookup( argv[i] ) );
- break;
- }
- }
- argNestLevel--;
- if( argNestLevel == 0 ) {
- libSearchList = Finalize( permStack, aLibSearchList );
- libFileSearchList = Finalize( permStack, aLibFileSearchList );
- fileList = Finalize( permStack, aFileList );
- incSearchList = Finalize( permStack, aIncSearchList );
- libExtList = Finalize( permStack, aLibExtList );
- }
- ValidatePlusArgs();
- }
- /************************************************
- Load
- - load and compile a file,
- return a parse tree
- *************************************************/
- set<string> loadedFiles;
- CNode* Load( const char* filename, int direct, int included )
- {
- if( loadedFiles.find(filename) != loadedFiles.end() ) {
- return NULL;
- }
- loadedFiles.insert(filename);
- MASSERT( codeList == NULL );
- CNode* code;
- modulesDirectlyDefined = direct;
- modulesIncluded = included;
- int success = lex_openFile( strdup(filename) );
- if( success ) {
- prog_parse();
- }
- code = codeList;
- codeList = NULL;
- tokenStack->Free(NULL);
- return code;
- }
- /*************************************************
- _Resolve
- - attempt of search of module in a library
- returns code for loaded module, NULL if
- not found
- *************************************************/
- static CNode* _Resolve( CModule* module, int reportError )
- {
- INT32 i;
- INT32 j;
-
- MASSERT( !module->IsDefined() || !module->ModuleIncluded() );
- if( module->IsDefined() ) {
- module->ModuleIncluded(TRUE);
- return cMODULE_DEF(module);
- }
- for( i = 0; libSearchList[i]; i++ ) {
- for( j = 0; libExtList[j] || j == 0; j++ ) {
- string path = libSearchList[i]->GetName();
- path += PATH_SEPARATOR;
- path += module->GetName();
- if( libExtList[j] ) {
- path += libExtList[j]->GetName();
- }
- if( access( path.c_str(), R_OK ) != 0 ) {
- continue;
- }
- CNode* code = Load( path.c_str(), FALSE, FALSE );
- if( module->IsDefined() &&
- !module->ModuleIncluded() ) {
- if( !quietFlag ) {
- logprintf( "Loaded '%s' from library '%s'\n",
- module->GetName(), path.c_str() );
- }
- module->ModuleIncluded( TRUE );
- return cMODULE_DEF(module);
- }
- }
- }
- for( i = 0; libFileSearchList[i]; i++ ) {
- const char* path = libFileSearchList[i]->GetName();
- if( access( path, R_OK ) != 0 ) {
- continue;
- }
- CNode* code = Load( path, FALSE, FALSE );
- if( module->IsDefined() && !module->ModuleIncluded() ) {
- if( !quietFlag ) {
- logprintf( "Loaded '%s' from library '%s'\n",
- module->GetName(), path );
- }
- module->ModuleIncluded( TRUE );
- return cMODULE_DEF(module);
- }
- }
- if( reportError ) {
- message( module->GetCoord(), mCRMOD, module->GetName() );
- }
- return NULL;
- }
- /************************************************
- ResolveModuleList
- - attempt to resolve all referenced modules
- return code for resolved modules
- ************************************************/
- static CNode* ResolveModuleList( CBackend* tool, CNode* n, int reportError )
- {
- CNode* result = NULL;
- if( n == NULL ) {
- return result;
- }
- switch( n->GetOp() ) {
- case eLIST:
- result = ResolveModuleList( tool,
- n->Arg<CNode*>(0), reportError );
- result = cLINK( ResolveModuleList( tool,
- n->Arg<CNode*>(1), reportError ),
- result );
- break;
- case eMODULE_DEF:
- {
- CModule* m = n->Arg<CModule*>(0);
- vector<CInstance*>& inst = *m->GetInstanceList();
- vector<CInstance*>::iterator p;
- for( p = inst.begin(); p != inst.end(); ++p ) {
- if( !tool->ResolveInstance( m, *p ) ) {
- continue;
- }
- CModule* def = (*p)->GetDefinition();
- if( !def->IsDefined() ||
- !def->ModuleIncluded() ) {
- result = cLINK( result,
- _Resolve( def, reportError ) );
- }
- }
- }
- break;
- case ePRAGMA:
- case eCOMMENT:
- case eVRQ:
- break;
- default:
- MASSERT( FALSE );
- }
- return result;
- }
- /************************************************
- ModulesResolved
- - returns TRUE if all modules are resolved
- ************************************************/
- static int ModulesResolved( CBackend* tool, CNode* n )
- {
- int result = TRUE;
- if( n == NULL ) {
- return result;
- }
- switch( n->GetOp() ) {
- case eLIST:
- result &= ModulesResolved( tool, n->Arg<CNode*>(0) );
- result &= ModulesResolved( tool, n->Arg<CNode*>(1) );
- break;
- case eMODULE_DEF:
- {
- CModule* m = n->Arg<CModule*>(0);
- vector<CInstance*>& inst = *m->GetInstanceList();
- vector<CInstance*>::iterator p;
- for( p = inst.begin(); p != inst.end(); ++p ) {
- if( !tool->ResolveInstance( m, *p ) ) {
- continue;
- }
- CModule* def = (*p)->GetDefinition();
- if( !def->IsDefined() ||
- !def->ModuleIncluded() ) {
- return FALSE;
- }
- }
- }
- break;
- case ePRAGMA:
- case eCOMMENT:
- case eVRQ:
- case eATTRIBUTE:
- break;
- default:
- MASSERT( FALSE );
- }
- return result;
- }
- /*************************************************
- LoadTools
- - load available tools
- *************************************************/
- static set<lt_dlhandle> toolHandles;
- void LoadTools()
- {
- CBackend* tool;
-
- /*
- * add vrq specific lib directory to search list
- */
- char* pld = getenv("PLUGIN_DIR");
- if( pld ) {
- char* ptr;
- ptr = strtok( strdup(pld), ":" );
- while( ptr != NULL ) {
- pluginPaths.push_back( ptr );
- ptr = strtok( NULL, ":" );
- }
- } else {
- pluginPaths.push_back( PKGLIBDIR );
- }
- /*
- * create built-in plugins
- */
- dumpVerilog = new CDumpVerilog();
- tools[dumpVerilog->GetToolName()] = dumpVerilog;
- tool = new CXProp();
- tools[tool->GetToolName()] = tool;
- #ifdef BUILTIN_SIM_PLUGIN
- sim = new CSim();
- tools[sim->GetToolName()] = sim;
- #endif
-
- int errors = lt_dlinit();
- if( errors ) {
- fprintf( stderr, "%s\n", lt_dlerror() );
- return;
- }
- list<string>::iterator pluginPath;
- for( pluginPath = pluginPaths.begin(); pluginPath != pluginPaths.end();
- ++pluginPath ) {
- DIR* dir;
- dir = opendir(pluginPath->c_str());
- if( dir ) {
- while(1) {
- struct dirent* entry = readdir( dir );
- if( !entry ) {
- break;
- }
- string path;
- path = *pluginPath;
- path += "/";
- path += entry->d_name;
- lt_dlhandle handle = lt_dlopen( path.c_str() );
- if( !handle ) {
- continue;
- }
- CBackend* (*sym)() = (CBackend*(*)())lt_dlsym( handle,
- "CreateToolInstance" );
- if( !sym ) {
- lt_dlclose( handle );
- continue;
- }
- /*
- * don't reinitialize tool twice. This can happen
- * because both *.la and *.so files are installed
- * in the plugin dir
- */
- if( toolHandles.count( handle ) ) {
- continue;
- }
- CBackend* t = (*sym)();
- if( !t ) {
- continue;
- }
- tools[t->GetToolName()] = t;
- toolHandles.insert( handle );
- }
- closedir( dir );
- }
- }
- }
- /*************************************************
- initial entry point
- *************************************************/
- static void DumpCode( FILE* f, CNode* n )
- {
- switch( n->GetOp() ) {
- case eLIST:
- if( n->Arg<CNode*>(0) ) DumpCode( f, n->Arg<CNode*>(0) );
- if( n->Arg<CNode*>(1) ) DumpCode( f, n->Arg<CNode*>(1) );
- break;
- case eMODULE_DEF:
- n->Arg<CModule*>(0)->Dump( f );
- break;
- case eCOMMENT:
- case eVRQ:
- break;
- default:
- fprintf( f, "unknown object or type %d\n", n->GetOp() );
- }
- }
- // #define DEFINE_TEST_HARNESS
- // #include "cnode_def.h"
- // #undef DEFINE_TEST_HARNESS
- int main( int argc, char** argv )
- {
- INT32 i;
- INT32 j;
- INT32 pass;
- CBackend* tool;
- // CNodeTestHarness();
- /*
- * error messages
- */
- mCRMOD = Message::RegisterWarning( NULL, Message::eERROR,
- "CRMOD", "cannot resolve module %s" );
-
- /*
- * load tools
- */
- LoadTools();
- /*
- * initialize global structures
- */
- CSymbol::SetObstack( permStack );
- Systask::Initialize();
- /*
- * parse command line arguments
- */
- argNestLevel = 0;
- ParseArguments( argc, const_cast<const char**>(argv) );
- if( debugFlag ) {
- CObstack::OnExitDumpStats();
- }
- /*
- * activate selected tools
- */
- list<CBackend*>::iterator ptr;
- for( ptr = enabledTools.begin(); ptr != enabledTools.end(); ++ptr ) {
- (*ptr)->Activate();
- ignoreVrqComments |= (*ptr)->IgnoreVrqComments();
- }
- /*
- * print copyright banner
- */
- if( !quietFlag ) {
- logprintf( "\n%s version %s, \n", VRQ, VERSION );
- logprintf( copyright );
- }
- /*
- * intialize subsystems
- */
- lex_init();
- parse_init();
- /*
- * parse each file and hand off to tools
- */
- list<CElement> input;
- list<CElement> output;
- int consumed = 0;
- if( !quietFlag ) {
- logprintf( "Parsing...\n" );
- }
- for( i = 0; fileList[i] != NULL; i++ ) {
- CNode* code = Load( fileList[i]->GetName(), TRUE, TRUE );
- const char* name = rindex( fileList[i]->GetName(), '/' );
- if( !name ) {
- name = fileList[i]->GetName();
- }
- output.push_back( CElement( name, 1, code ) );
- if( dumpFlag ) {
- fprintf( stdout, "MACRO definitions:\n" );
- fprintf( stdout, "------------------\n" );
- macroSymtab.Dump( stdout, 1 );
- fprintf( stdout, "global definitions:\n" );
- fprintf( stdout, "------------------\n" );
- definitionSymtab.Dump( stdout, 1 );
- fprintf( stdout, "MODULE definitions:\n" );
- fprintf( stdout, "------------------\n" );
- DumpCode( stdout, code );
- }
- }
- // CSymbol::DumpStats();
- /*
- * bail out if errors occurred
- */
- if( errorCount ) {
- goto DONE;
- }
- /*
- * run each tool in chain
- */
- for( ptr = enabledTools.begin(); ptr != enabledTools.end(); ++ptr ) {
- input.erase( input.begin(), input.end() );
- list<CElement>::iterator eptr;
- for( eptr = output.begin(); eptr != output.end(); ++eptr ) {
- /*
- * if tools requires it resolve all module references
- * Make 2 pass to see if search found other modules
- */
- int pass = 1;
- CNode* code = eptr->Code();
- while( (*ptr)->ResolveModules() &&
- !ModulesResolved( *ptr, code ) ) {
- CNode* rcode = ResolveModuleList( *ptr, code,
- (*ptr)->RequireModuleResolution() && pass>1 );
- if( pass > 1 && !rcode ) {
- break;
- }
- pass++;
- code = cLINK( rcode, code );
- }
- eptr->Code( code );
- input.push_back( *eptr );
- }
- output.erase( output.begin(), output.end() );
- if( errorCount ) {
- goto DONE;
- }
- CBackend* tool = (*ptr);
- if( !quietFlag ) {
- logprintf( "Executing tool %s...\n", tool->GetToolName() );
- }
- /*
- * use plugin storage manager by default
- */
- CNode::SetBuildStack( pluginStack );
- try {
- tool->Process( input, output );
- } catch( CBackendAbort ) {
- abort();
- } catch( CBackendFail ) {
- goto DONE;
- } catch( CBackendExit ) {
- // success!
- } catch( ... ) {
- abort();
- }
- /*
- * restore environment
- */
- CNode::ResetBuildStack();
- if( output.size() == 0 ) {
- output = input;
- consumed = 1;
- }
- }
- /*
- * If output hasn't be consumed run dump tool
- */
- if( !consumed && output.size() && errorCount == 0 ) {
- if( !quietFlag ) {
- logprintf( "Executing tool %s...\n",
- dumpVerilog->GetToolName() );
- }
- list<CElement> dummy;
- try {
- dumpVerilog->Process( output, dummy );
- } catch( CBackendAbort ) {
- abort();
- } catch( CBackendFail ) {
- goto DONE;
- } catch( CBackendExit ) {
- // success!
- } catch( ... ) {
- abort();
- }
- }
- DONE:
- // logprintf( "Total Memory Allocated = %d\n", totalMem );
- if( !quietFlag ) {
- logprintf( "%d Errors, %d Warnings\n", errorCount, warningCount );
- }
- return (errorCount != 0);
- }