vrq

Example Plugin

This example plugin searches the parsed code and finds register and net declarations and references.

A report of whether the variables are declared and how many times they are referenced is printed. It also issues warnings for any variables that are declared but not referenced.

The makefile for building the plugin (for linux based systems) follows (Makefile-example1):

#/*-----------------------------------------------------------------------------
# * 	Copyright (c) 1997-2009 Mark Hummel DBA Raquette Software.
# *		All rights reserved
# *
# *    This file contains source code written by Raquette Software, 
# *    68 Stewart Street, Franklin MA 02038. It may not be used without 
# *    express written permission. The expression of the information 
# *    contained herein is protected under federal copyright laws and 
# *    all copying without permission is prohibited and may be subject 
# *    to criminal penalties. The Author assumes no responsibility for 
# *    errors, omissions, or damages caused by the use of these programs 
# *    or from use of the information contained herein.
# *
# *-----------------------------------------------------------------------------
# */

#
# Extract installation flags and paths for vrq
#
VRQ_VERSION = $(shell vrq --version|head -n 1|cut -c 5-|cut -d , -f1)
PLUGIN_DIR = $(shell vrq --pkglibdir)
INCLUDE_DIR = $(shell vrq --includedir)
CXXFLAGS = $(shell vrq --cflags)
LDFLAGS = $(shell vrq --ldflags)

#
# name of plugin
#
PLUGIN=example1

#
# Build object file
#
all:	$(PLUGIN).so

$(PLUGIN).o: $(PLUGIN).cc $(PLUGIN).h
	$(CXX) -I . -I $(INCLUDE_DIR) $(CXXFLAGS) \
		-DVRQ_VERSION=\"$(VRQ_VERSION)\" -c $<  -fPIC -DPIC -o $@ 

#
# Build DLL
#
$(PLUGIN).so: $(PLUGIN).o
	$(CXX) $(LDFLAGS) -shared $< -Wl,-soname -Wl,$@ -o $@

#
# Install plugin
#
install: $(PLUGIN).so
	install -c '$<' $(PLUGIN_DIR)

#
# Print installation flags and paths
#
env:
	echo "VRQ_VERSION: $(VRQ_VERSION)"
	echo "PLUGIN_DIR: $(PLUGIN_DIR)"
	echo "INCLUDE_DIR: $(INCLUDE_DIR)"
	echo "CXXFLAGS: $(CXXFLAGS)"
	echo "LDFLAGS: $(LDFLAGS)"

#
# remove built files
#
clean:
	-rm $(PLUGIN).o $(PLUGIN).so


The header file for the plugin is below (example1.h):

/*-----------------------------------------------------------------------------
 * 	Copyright (c) 1997-2009 Mark Hummel DBA Raquette Software.
 *		All rights reserved
 *
 *    This file contains source code written by Raquette Software, 
 *    68 Stewart Street, Franklin MA 02038. It may not be used without 
 *    express written permission. The expression of the information 
 *    contained herein is protected under federal copyright laws and 
 *    all copying without permission is prohibited and may be subject 
 *    to criminal penalties. The Author assumes no responsibility for 
 *    errors, omissions, or damages caused by the use of these programs 
 *    or from use of the information contained herein.
 *
 *-----------------------------------------------------------------------------
 */
/******************************************************************************
 *
 *
 *	   example1.h
 *	   - example plugin
 *		- 
 *
 ******************************************************************************
 */

#ifndef EXAMPLE1_H 
#define EXAMPLE1_H 

/*
 * include vrq headers
 */
#include "plugin.h"
#include <map>

/*
 * Plugin tools implement a subclass of CBackend.
 */
class CExample1 : public CBackend 
{
private:
    Message* mVIDNR;	// error message object
    int listNets;	// non-zero if +example-list-nets has
			// been specified
    int listRegs;	// non-zero if +example-list-regs has 
			// been specified
public:
    /*
     * data structure used to record variable info
     */
    struct DeclRecord {
	CDecl*   decl;	    // declaration object
	CModule* module;    // containing module
	int      refCount;  // number of references to declaration
	int      declared;  // variable has been explicitly declared
    };
private:
	map<CDecl*,DeclRecord> decl2Record; // map of variable to 
					    // info data structure.
public:
	/*
 	 * Methods
 	 */
	CExample1( void );
	virtual char* GetToolName( void );
	virtual char* GetToolDescription( void );
        virtual int AcceptAllPlusArgs( void );
        virtual int HideTool();
        virtual int IgnoreVrqComments();
	virtual int ResolveModules();
	virtual int ResolveInstance( CModule*, CInstance* );
	virtual void Activate();
	virtual void Process( list<CElement>& inputList,
			      list<CElement>& outputList );
};

#endif // EXAMPLE1_H

The source for the plugin follows (example1.cc):

/*-----------------------------------------------------------------------------
 * 	Copyright (c) 1997-2009 Mark Hummel DBA Raquette Software.
 *		All rights reserved
 *
 *    This file contains source code written by Raquette Software, 
 *    68 Stewart Street, Franklin MA 02038. It may not be used without 
 *    express written permission. The expression of the information 
 *    contained herein is protected under federal copyright laws and 
 *    all copying without permission is prohibited and may be subject 
 *    to criminal penalties. The Author assumes no responsibility for 
 *    errors, omissions, or damages caused by the use of these programs 
 *    or from use of the information contained herein.
 *
 *-----------------------------------------------------------------------------
 */
/******************************************************************************
 *
 *
 *	   example1.cc
 *	   - methods for example plugin
 *
 ******************************************************************************
 */
						

#include "example1.h"

/************************************************
 	CreateToolInstance
	- entry point for dll. Vrq will 
	  call this entry point (must be C code)
	  to create and initialize the tool.
	  If tool creation fails, return NULL and
	  vrq will ignore DLL.
 ************************************************/
extern "C" {
    CBackend* CreateToolInstance()
    {
	/*
 	 * Only initialize the tool if it was built for
 	 * the running version of vrq.
 	 */
        if( strcmp( VRQ_VERSION, VrqVersionString() ) ) {
    	    return NULL;
        }
	/*
 	 * Create tool and return it.
 	 */
        return new CExample1();
    }
}

/************************************************
 	Constructor
	- Initialize tool
 ************************************************/
CExample1::CExample1( ) 
{
     /*
      * Initialize local variables
      */
     listNets = 0;
     listRegs = 0;

     /*
      * Register switches (plus args) for use in the vrq help system
      */
     RegisterSwitch("+example1-list-nets", "print list of declared nets");
     RegisterSwitch("+example1-list-regs", "print list of declared regs");

     /*
      * Predeclare all the warning and error messages for later use.
      */
     mVIDNR = Message::RegisterWarning( this, Message::eWARNING,
	 	"VIDNR", "variable '%s::%s' is declared but not referenced\n",
		 "<module>", "<variable>" );
}

/************************************************
	AcceptAllPlusArgs
 	- return TRUE if tool accepts arbitrary
	  plusargs.
 ************************************************/
int CExample1::AcceptAllPlusArgs( void ) 
{ 
    /*
     * Tool does not support arbitary plusargs
     */
    return FALSE; 
}

/************************************************
	HideTool
	- return TRUE if tool should be hidden
	  from help system. This allows a tool
	  to be functional and hidden.
 ***********************************************/
int CExample1::HideTool() 
{ 
    return FALSE;
}

/************************************************
	IgnoreVrqComments
	- return TRUE if tool requires lexer to
	  treat vrq translate_on/off pragmas
	  as pure comments.
 ***********************************************/
int CExample1::IgnoreVrqComments() 
{ 
    return FALSE; 
}

/************************************************
	ResolveModules
	- return TRUE if tool requires all
	  module references to be resolved.
	  This is done by search specified
	  library search paths.
 ***********************************************/
int CExample1::ResolveModules() 
{ 
    return FALSE;
}

/************************************************
	ResolveInstance
	- return TRUE if tool requires the
	  given module reference to be resolved.
	  This is allows a tool to implement a
	  fine grain filter on what must be resolved.
	  Note this only called if ResolvedModules
	  returns TRUE.
 ***********************************************/
int CExample1::ResolveInstance( CModule*, CInstance* ) 
{
    return FALSE;
}

/************************************************
	Activate
	- This routine is called before a tool
	  is invoked. It is only called once
	  and will only be called if the tool
	  will be used in a pipeline.
 ***********************************************/
void CExample1::Activate() 
{
}


/************************************************
	GetToolName
 	- return name of tool
 ************************************************/
char* CExample1::GetToolName( void )
{
    static char	toolName[] = "example1";

    return toolName;
}

/************************************************
	GetToolDescription
 	- return description of tool. This
	  text is used in vrq help text, man pages, etc.
 ************************************************/
char* CExample1::GetToolDescription( void )
{
    static char	toolDescription[] = "Example plugin that dumps a"
				    " list of declare registers or nets";

    return toolDescription;
}

/************************************************
	FindDecls
	- callback routine used to gather a list of 
	  variable statistics. 	
 ***********************************************/
static CModule* currentModule = NULL;
int FindDecls( CNode* n, void* arg )
{
    map<CDecl*,CExample1::DeclRecord>* d2r = 
			(map<CDecl*,CExample1::DeclRecord>*)arg;
    CDecl* decl;

    switch( n->GetOp() ) {
    case eMODULE_DEF:
	currentModule = n->Arg<CModule*>(0);
	break;
    case ePORT_DECL:
	decl = n->Arg<CPortDir*>(0)->GetDecl();
	if( decl ) {
	    if( d2r->find(decl) == d2r->end() ) {
	        (*d2r)[decl].decl     = decl;
	        (*d2r)[decl].module   = NULL;
	        (*d2r)[decl].declared = 0;
	        (*d2r)[decl].refCount = 0;
	        (*d2r)[decl].module   = currentModule;
	    }
	    (*d2r)[decl].declared = 1;
	    (*d2r)[decl].refCount++;
	    (*d2r)[decl].module = currentModule;
	}
	break;
    case eREG_DECL: 
	decl = n->Arg<CReg*>(0);
	if( d2r->find(decl) == d2r->end() ) {
	    (*d2r)[decl].decl     = decl;
	    (*d2r)[decl].module   = NULL;
	    (*d2r)[decl].declared = 0;
	    (*d2r)[decl].refCount = 0;
	    (*d2r)[decl].module   = currentModule;
	}
	(*d2r)[decl].declared = 1;
	break;
    case eNET_DECL:
	decl = n->Arg<CNet*>(0);
	if( d2r->find(decl) == d2r->end() ) {
	    (*d2r)[decl].decl     = decl;
	    (*d2r)[decl].module   = NULL;
	    (*d2r)[decl].declared = 0;
	    (*d2r)[decl].refCount = 0;
	    (*d2r)[decl].module   = currentModule;
	}
	(*d2r)[decl].declared = 1;
	break;
    case eREG_REF:
	decl = n->Arg<CReg*>(0);
	if( d2r->find(decl) == d2r->end() ) {
	    (*d2r)[decl].decl     = decl;
	    (*d2r)[decl].module   = NULL;
	    (*d2r)[decl].declared = 0;
	    (*d2r)[decl].refCount = 0;
	    (*d2r)[decl].module   = currentModule;
	}
	(*d2r)[decl].refCount++;
	break;
    case eNET_REF:
	decl = n->Arg<CNet*>(0);
	if( d2r->find(decl) == d2r->end() ) {
	    (*d2r)[decl].decl     = decl;
	    (*d2r)[decl].module   = NULL;
	    (*d2r)[decl].declared = 0;
	    (*d2r)[decl].refCount = 0;
	    (*d2r)[decl].module   = currentModule;
	}
	(*d2r)[decl].refCount++;
	break;
    }

    /*
     * Don't terminate search
     */
    return 1;
}


/************************************************
	Process
	- process a compilation unit 
 ************************************************/
void CExample1::Process( list<CElement>& inputList,
		       list<CElement>& outputList )
{
    /*
     * check whether switches have been specified.
     */
    listNets = GetPlusArg( "example1-list-nets" ) != NULL;
    listRegs = GetPlusArg( "example1-list-regs" ) != NULL;

    /*
     * process each compilation unit
     */
    list<CElement>::iterator ptr;
    for( ptr = inputList.begin(); ptr != inputList.end(); ++ptr ) {
	/*
 	 * Transverse the entire code tree for the given compilation
 	 * unit. For each node FindDecls will be called to 
 	 * accumulate variable statistics.
 	 */
        CNode* code = ptr->Code(); 
	code->PreVisit1( FindDecls, &decl2Record );
    }


    /*
     * iterate through the list of variables and flag
     * any that are declared but not referenced.
     */
    map<CDecl*,DeclRecord>::iterator mptr;
    for( mptr = decl2Record.begin(); mptr != decl2Record.end(); ++mptr ) {
	int declared = mptr->second.declared;
	int refCount = mptr->second.refCount;
	CModule* module = mptr->second.module;
	CDecl* decl = mptr->second.decl;
	if( declared && refCount == 0 ) {
    	    message( decl->GetCoord(), mVIDNR, module->GetName(), decl->GetName() );
	}
    }

    /*
     * iterate through the list of variables and dump the
     * statistics that have been collected.
     */
    for( mptr = decl2Record.begin(); mptr != decl2Record.end(); ++mptr ) {
	int declared = mptr->second.declared;
	int refCount = mptr->second.refCount;
	CModule* module = mptr->second.module;
	CDecl* decl = mptr->second.decl;
	if( decl->GetClass() == eNET && !listNets ) {
	    continue;
	}
	if( decl->GetClass() == eREG && !listRegs ) {
	    continue;
	}
	logprintf( "decl %s::%s: declared=%d reference count=%d\n",
		   module->GetName(), decl->GetName(), declared, refCount );
    }

}