2006-08-26 13:35:28 +02:00
// $Id$
//*************************************************************************
// DESCRIPTION: Verilator: Emit C++ for tree
//
// Code available from: http://www.veripool.com/verilator
//
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
//
//*************************************************************************
//
// Copyright 2003-2006 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// General Public License or the Perl Artistic License.
//
// Verilator 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.
//
//*************************************************************************
# include "config.h"
# include <stdio.h>
# include <stdarg.h>
# include <unistd.h>
# include <math.h>
# include <map>
# include <vector>
# include <algorithm>
# include "V3Global.h"
# include "V3EmitC.h"
# include "V3EmitCBase.h"
# define VL_VALUE_STRING_MAX_WIDTH 1024 // We use a static char array in VL_VALUE_STRING
//######################################################################
// Coverage ID tracking
class EmitCoverIds {
// TYPES
typedef map < AstCoverDecl * , int > CoverIdMap ;
// MEMBERS
CoverIdMap m_coverIds ; // Remapping of coverage IDs to per-module value
int m_coverIdsSize ; // Size of m_coverIds (to avoid O(n^2) insert)
// METHODS
public :
void clear ( ) {
m_coverIds . clear ( ) ;
m_coverIdsSize = 0 ;
}
int size ( ) const { return m_coverIdsSize ; }
int remap ( AstCoverDecl * declp ) {
// Make cover ID for this point, unique on this module
CoverIdMap : : iterator it = m_coverIds . find ( declp ) ;
if ( it = = m_coverIds . end ( ) ) {
m_coverIds . insert ( make_pair ( declp , m_coverIdsSize + + ) ) ; // Remapping of coverage IDs to per-module value
return m_coverIdsSize - 1 ;
} else {
return it - > second ;
}
}
EmitCoverIds ( ) : m_coverIdsSize ( 0 ) { }
~ EmitCoverIds ( ) { }
} ;
//######################################################################
// Emit statements and math operators
class EmitCStmts : public EmitCBaseVisitor {
private :
bool m_suppressSemi ;
AstVarRef * m_wideTempRefp ; // Variable that _WW macros should be setting
vector < AstVar * > m_ctorVarsVec ; // All variables in constructor order
public :
EmitCoverIds m_coverIds ; // Coverage ID remapping
public :
//int debug() { return 9; }
// METHODS
void displayEmit ( AstDisplay * nodep ) ;
string displayFormat ( AstNode * widthNode , string in ,
char fmtLetter , bool padZero , bool reallyString ) ;
void displayArg ( AstDisplay * dispp , AstNode * * elistp , string fmt , char fmtLetter ) ;
void emitVarDecl ( AstVar * nodep , const string & prefixIfImp ) ;
2006-08-29 02:58:48 +02:00
typedef enum { EVL_IO , EVL_SIG , EVL_TEMP , EVL_STATIC , EVL_ALL } EisWhich ;
2006-08-26 13:35:28 +02:00
void emitVarList ( AstNode * firstp , EisWhich which , const string & prefixIfImp ) ;
void emitVarCtors ( ) ;
bool emitSimpleOk ( AstNodeMath * nodep ) ;
void emitIQW ( AstNode * nodep ) {
puts ( nodep - > isWide ( ) ? " W " : ( nodep - > isQuad ( ) ? " Q " : " I " ) ) ;
}
void emitOpName ( AstNode * nodep , const string & name ) ;
string cFuncArgs ( AstCFunc * nodep ) {
// Return argument list for given C function
string args = nodep - > argTypes ( ) ;
if ( args = = " " ) {
// Might be a user function with argument list.
for ( AstNode * stmtp = nodep - > argsp ( ) ; stmtp ; stmtp = stmtp - > nextp ( ) ) {
if ( AstVar * portp = stmtp - > castVar ( ) ) {
if ( portp - > isIO ( ) & & ! portp - > isFuncReturn ( ) ) {
if ( args ! = " " ) args + = " , " ;
args + = portp - > cType ( ) ;
if ( portp - > isOutput ( ) ) args + = " & " ;
args + = " " + portp - > name ( ) ;
}
}
}
}
return args ;
}
// VISITORS
virtual void visit ( AstNodeAssign * nodep , AstNUser * ) {
bool paren = true ; bool decind = false ;
if ( AstSel * selp = nodep - > lhsp ( ) - > castSel ( ) ) {
if ( selp - > widthMin ( ) = = 1 ) {
putbs ( " VL_ASSIGNBIT_ " ) ;
emitIQW ( selp - > fromp ( ) ) ;
if ( nodep - > rhsp ( ) - > isAllOnesV ( ) ) {
putbs ( " O( " ) ;
} else {
putbs ( " I( " ) ;
}
puts ( cvtToStr ( nodep - > widthMin ( ) ) + " , " ) ;
selp - > lsbp ( ) - > iterateAndNext ( * this ) ; puts ( " , " ) ;
selp - > fromp ( ) - > iterateAndNext ( * this ) ; puts ( " , " ) ;
} else {
putbs ( " VL_ASSIGNSEL_ " ) ;
emitIQW ( selp - > fromp ( ) ) ;
putbs ( " II " ) ;
emitIQW ( nodep - > rhsp ( ) ) ;
puts ( " ( " ) ;
puts ( cvtToStr ( nodep - > widthMin ( ) ) + " , " ) ;
selp - > lsbp ( ) - > iterateAndNext ( * this ) ; puts ( " , " ) ;
selp - > fromp ( ) - > iterateAndNext ( * this ) ; puts ( " , " ) ;
}
} else if ( nodep - > lhsp ( ) - > castVarRef ( )
& & nodep - > lhsp ( ) - > castVarRef ( ) - > varp ( ) - > isSc ( ) ) {
putbs ( " VL_ASSIGN_ " ) ; // Set a systemC variable
if ( nodep - > lhsp ( ) - > castVarRef ( ) - > varp ( ) - > isScQuad ( ) ) puts ( " SQ " ) ;
else puts ( " S " ) ;
emitIQW ( nodep ) ;
puts ( " ( " ) ;
puts ( cvtToStr ( nodep - > widthMin ( ) ) + " , " ) ;
nodep - > lhsp ( ) - > iterateAndNext ( * this ) ; puts ( " , " ) ;
} else if ( nodep - > rhsp ( ) - > castVarRef ( )
& & nodep - > rhsp ( ) - > castVarRef ( ) - > varp ( ) - > isSc ( ) ) {
putbs ( " VL_ASSIGN_ " ) ; // Get a systemC variable
emitIQW ( nodep ) ;
if ( nodep - > rhsp ( ) - > castVarRef ( ) - > varp ( ) - > isScQuad ( ) ) puts ( " SQ( " ) ;
else puts ( " S( " ) ;
puts ( cvtToStr ( nodep - > widthMin ( ) ) + " , " ) ;
nodep - > lhsp ( ) - > iterateAndNext ( * this ) ; puts ( " , " ) ;
} else if ( nodep - > isWide ( )
& & nodep - > lhsp ( ) - > castVarRef ( )
& & ! nodep - > rhsp ( ) - > castVarRef ( )
& & ! nodep - > rhsp ( ) - > castArraySel ( ) ) {
// Wide functions assign into the array directly, don't need separate assign statement
m_wideTempRefp = nodep - > lhsp ( ) - > castVarRef ( ) ;
paren = false ;
} else if ( nodep - > isWide ( ) ) {
putbs ( " VL_ASSIGN_W( " ) ;
puts ( cvtToStr ( nodep - > widthMin ( ) ) + " , " ) ;
nodep - > lhsp ( ) - > iterateAndNext ( * this ) ; puts ( " , " ) ;
} else {
paren = false ;
nodep - > lhsp ( ) - > iterateAndNext ( * this ) ;
puts ( " " ) ;
ofp ( ) - > blockInc ( ) ; decind = true ;
if ( ! nodep - > rhsp ( ) - > castConst ( ) ) ofp ( ) - > putBreak ( ) ;
puts ( " = " ) ;
}
nodep - > rhsp ( ) - > iterateAndNext ( * this ) ;
if ( paren ) puts ( " ) " ) ;
if ( decind ) ofp ( ) - > blockDec ( ) ;
if ( ! m_suppressSemi ) puts ( " ; \n " ) ;
}
virtual void visit ( AstCCall * nodep , AstNUser * ) {
puts ( nodep - > hiername ( ) ) ;
puts ( nodep - > funcp ( ) - > name ( ) ) ;
puts ( " ( " ) ;
2006-08-30 23:07:55 +02:00
puts ( nodep - > argTypes ( ) ) ;
bool comma = ( nodep - > argTypes ( ) ! = " " ) ;
2006-08-26 13:35:28 +02:00
for ( AstNode * subnodep = nodep - > argsp ( ) ; subnodep ; subnodep = subnodep - > nextp ( ) ) {
2006-08-30 23:07:55 +02:00
if ( comma ) puts ( " , " ) ;
2006-08-26 13:35:28 +02:00
subnodep - > accept ( * this ) ;
2006-08-30 23:07:55 +02:00
comma = true ;
2006-08-26 13:35:28 +02:00
}
if ( nodep - > backp ( ) - > castNodeMath ( ) | | nodep - > backp ( ) - > castCReturn ( ) ) {
// We should have a separate CCall for math and statement usage, but...
puts ( " ) " ) ;
} else {
puts ( " ); \n " ) ;
}
}
virtual void visit ( AstNodeCase * nodep , AstNUser * ) {
// In V3Case...
nodep - > v3fatalSrc ( " Case statements should have been reduced out \n " ) ;
}
virtual void visit ( AstComment * nodep , AstNUser * ) {
puts ( ( string ) " // " + nodep - > name ( ) + " at " + nodep - > fileline ( ) - > ascii ( ) + " \n " ) ;
nodep - > iterateChildren ( * this ) ;
}
virtual void visit ( AstCoverDecl * nodep , AstNUser * ) {
2006-08-30 03:14:29 +02:00
puts ( " __vlCoverInsert( " ) ; // As Declared in emitCoverageDecl
2006-08-26 13:35:28 +02:00
puts ( " &__Vcoverage[ " ) ;
puts ( cvtToStr ( m_coverIds . remap ( nodep ) ) ) ; puts ( " ] " ) ;
puts ( " , \" " ) ; puts ( nodep - > fileline ( ) - > filebasename ( ) ) ; puts ( " \" " ) ;
puts ( " , " ) ; puts ( cvtToStr ( nodep - > fileline ( ) - > lineno ( ) ) ) ;
puts ( " , " ) ; puts ( cvtToStr ( nodep - > column ( ) ) ) ;
puts ( " , \" " ) ; puts ( nodep - > hier ( ) ) ; puts ( " \" " ) ;
puts ( " , \" " ) ; puts ( nodep - > typeText ( ) ) ; puts ( " \" " ) ;
puts ( " , \" " ) ; puts ( nodep - > comment ( ) ) ; puts ( " \" " ) ;
puts ( " ); \n " ) ;
}
virtual void visit ( AstCoverInc * nodep , AstNUser * ) {
2006-09-12 02:55:27 +02:00
puts ( " ++this->__Vcoverage[ " ) ;
2006-08-26 13:35:28 +02:00
puts ( cvtToStr ( m_coverIds . remap ( nodep - > declp ( ) ) ) ) ; puts ( " ]; \n " ) ;
}
virtual void visit ( AstCReturn * nodep , AstNUser * ) {
puts ( " return ( " ) ;
nodep - > lhsp ( ) - > iterateAndNext ( * this ) ;
puts ( " ); \n " ) ;
}
virtual void visit ( AstDisplay * nodep , AstNUser * ) ; // BELOW
virtual void visit ( AstFOpen * nodep , AstNUser * ) {
nodep - > filep ( ) - > iterateAndNext ( * this ) ;
puts ( " = VL_FOPEN_ " ) ;
emitIQW ( nodep - > filenamep ( ) ) ;
emitIQW ( nodep - > modep ( ) ) ;
if ( nodep - > modep ( ) - > width ( ) > 4 * 8 ) nodep - > modep ( ) - > v3error ( " $fopen mode should be <= 4 characters " ) ;
puts ( " ( " ) ;
if ( nodep - > filenamep ( ) - > isWide ( ) ) puts ( cvtToStr ( nodep - > filenamep ( ) - > widthWords ( ) ) ) ;
if ( nodep - > filenamep ( ) - > widthWords ( ) > VL_TO_STRING_MAX_WORDS ) {
nodep - > v3error ( " String of " < < nodep - > filenamep ( ) - > width ( ) < < " bits exceeds hardcoded limit VL_TO_STRING_MAX_WORDS in verilatedos.h \n " ) ;
}
putbs ( " , " ) ;
nodep - > filenamep ( ) - > iterateAndNext ( * this ) ;
putbs ( " , " ) ;
nodep - > modep ( ) - > iterateAndNext ( * this ) ;
puts ( " ); \n " ) ;
}
virtual void visit ( AstFClose * nodep , AstNUser * ) {
puts ( " if ( " ) ;
nodep - > filep ( ) - > iterateAndNext ( * this ) ;
puts ( " ) { fclose (VL_CVT_Q_FP( " ) ;
nodep - > filep ( ) - > iterateAndNext ( * this ) ;
puts ( " )); " ) ;
nodep - > filep ( ) - > iterateAndNext ( * this ) ; // For saftey, so user doesn't later WRITE with it.
puts ( " =0; } \n " ) ;
}
virtual void visit ( AstWhile * nodep , AstNUser * ) {
nodep - > precondsp ( ) - > iterateAndNext ( * this ) ;
puts ( " while ( " ) ;
nodep - > condp ( ) - > iterateAndNext ( * this ) ;
puts ( " ) { \n " ) ;
nodep - > bodysp ( ) - > iterateAndNext ( * this ) ;
nodep - > precondsp ( ) - > iterateAndNext ( * this ) ; // Need to recompute before next loop
puts ( " } \n " ) ;
}
virtual void visit ( AstNodeIf * nodep , AstNUser * ) {
puts ( " if ( " ) ;
if ( nodep - > branchPred ( ) ! = AstBranchPred : : UNKNOWN ) {
puts ( nodep - > branchPred ( ) . ascii ( ) ) ; puts ( " ( " ) ;
}
nodep - > condp ( ) - > iterateAndNext ( * this ) ;
if ( nodep - > branchPred ( ) ! = AstBranchPred : : UNKNOWN ) puts ( " ) " ) ;
puts ( " ) { \n " ) ;
nodep - > ifsp ( ) - > iterateAndNext ( * this ) ;
if ( nodep - > elsesp ( ) ) {
puts ( " } else { \n " ) ;
nodep - > elsesp ( ) - > iterateAndNext ( * this ) ;
}
puts ( " } \n " ) ;
}
virtual void visit ( AstStop * nodep , AstNUser * ) {
puts ( " vl_stop( \" " ) ;
puts ( nodep - > fileline ( ) - > filename ( ) ) ;
puts ( " \" , " ) ;
puts ( cvtToStr ( nodep - > fileline ( ) - > lineno ( ) ) ) ;
puts ( " , \" \" ); \n " ) ;
}
virtual void visit ( AstFinish * nodep , AstNUser * ) {
puts ( " vl_finish( \" " ) ;
puts ( nodep - > fileline ( ) - > filename ( ) ) ;
puts ( " \" , " ) ;
puts ( cvtToStr ( nodep - > fileline ( ) - > lineno ( ) ) ) ;
puts ( " , \" \" ); \n " ) ;
}
virtual void visit ( AstText * nodep , AstNUser * ) {
ofp ( ) - > putsNoTracking ( nodep - > text ( ) ) ;
}
virtual void visit ( AstCStmt * nodep , AstNUser * ) {
nodep - > bodysp ( ) - > iterateAndNext ( * this ) ;
}
virtual void visit ( AstCMath * nodep , AstNUser * ) {
nodep - > bodysp ( ) - > iterateAndNext ( * this ) ;
}
virtual void visit ( AstUCStmt * nodep , AstNUser * ) {
puts ( " // $c statement at " + nodep - > fileline ( ) - > ascii ( ) + " \n " ) ;
nodep - > bodysp ( ) - > iterateAndNext ( * this ) ;
puts ( " \n " ) ;
}
virtual void visit ( AstUCFunc * nodep , AstNUser * ) {
puts ( " \n " ) ;
puts ( " // $c function at " + nodep - > fileline ( ) - > ascii ( ) + " \n " ) ;
nodep - > bodysp ( ) - > iterateAndNext ( * this ) ;
puts ( " \n " ) ;
}
// Operators
virtual void visit ( AstNodeTermop * nodep , AstNUser * ) {
emitOpName ( nodep , nodep - > emitOperator ( ) ) ;
puts ( " ) " ) ;
}
virtual void visit ( AstNodeUniop * nodep , AstNUser * ) {
if ( emitSimpleOk ( nodep ) ) {
putbs ( " ( " ) ; puts ( nodep - > emitSimpleOperator ( ) ) ; puts ( " " ) ;
} else {
emitOpName ( nodep , nodep - > emitOperator ( ) ) ;
}
nodep - > lhsp ( ) - > iterateAndNext ( * this ) ; puts ( " ) " ) ;
}
virtual void visit ( AstNodeBiop * nodep , AstNUser * ) {
if ( emitSimpleOk ( nodep ) ) {
putbs ( " ( " ) ; nodep - > lhsp ( ) - > iterateAndNext ( * this ) ;
puts ( " " ) ; putbs ( nodep - > emitSimpleOperator ( ) ) ; puts ( " " ) ;
} else {
emitOpName ( nodep , nodep - > emitOperator ( ) ) ;
nodep - > lhsp ( ) - > iterateAndNext ( * this ) ; puts ( " , " ) ;
}
nodep - > rhsp ( ) - > iterateAndNext ( * this ) ; puts ( " ) " ) ;
}
virtual void visit ( AstRedXor * nodep , AstNUser * vup ) {
if ( nodep - > lhsp ( ) - > isWide ( ) ) {
visit ( nodep - > castNodeUniop ( ) , vup ) ;
} else {
putbs ( " VL_REDXOR_ " ) ;
puts ( cvtToStr ( nodep - > lhsp ( ) - > widthPow2 ( ) ) ) ;
puts ( " ( " ) ;
nodep - > lhsp ( ) - > iterateAndNext ( * this ) ;
puts ( " ) " ) ;
}
}
virtual void visit ( AstMulS * nodep , AstNUser * vup ) {
if ( nodep - > widthWords ( ) > VL_MULS_MAX_WORDS ) {
nodep - > v3error ( " Signed multiply of " < < nodep - > width ( ) < < " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h \n " ) ;
}
visit ( nodep - > castNodeBiop ( ) , vup ) ;
}
virtual void visit ( AstCast * nodep , AstNUser * ) {
// Extending a value of the same word width is just a NOP.
if ( nodep - > size ( ) > VL_WORDSIZE ) {
puts ( " (QData)( " ) ;
} else {
puts ( " (IData)( " ) ;
}
nodep - > lhsp ( ) - > iterateAndNext ( * this ) ;
puts ( " ) " ) ;
}
virtual void visit ( AstNodeCond * nodep , AstNUser * ) {
// Widths match up already, so we'll just use C++'s operator w/o any temps.
if ( nodep - > expr1p ( ) - > isWide ( ) ) {
emitOpName ( nodep , nodep - > emitOperator ( ) ) ;
nodep - > condp ( ) - > iterateAndNext ( * this ) ; puts ( " , " ) ;
nodep - > expr1p ( ) - > iterateAndNext ( * this ) ; puts ( " , " ) ;
nodep - > expr2p ( ) - > iterateAndNext ( * this ) ; puts ( " ) " ) ;
} else {
putbs ( " ( " ) ;
nodep - > condp ( ) - > iterateAndNext ( * this ) ; putbs ( " ? " ) ;
nodep - > expr1p ( ) - > iterateAndNext ( * this ) ; putbs ( " : " ) ;
nodep - > expr2p ( ) - > iterateAndNext ( * this ) ; puts ( " ) " ) ;
}
}
virtual void visit ( AstSel * nodep , AstNUser * ) {
// Note ASSIGN checks for this on a LHS
if ( nodep - > widthp ( ) - > isOne ( ) ) {
emitOpName ( nodep , " VL_BITSEL " ) ;
nodep - > fromp ( ) - > iterateAndNext ( * this ) ; puts ( " , " ) ;
nodep - > lsbp ( ) - > iterateAndNext ( * this ) ; puts ( " ) " ) ;
} else {
emitOpName ( nodep , " VL_SEL " ) ;
nodep - > fromp ( ) - > iterateAndNext ( * this ) ; puts ( " , " ) ;
nodep - > lsbp ( ) - > iterateAndNext ( * this ) ; puts ( " , " ) ;
nodep - > widthp ( ) - > iterateAndNext ( * this ) ; puts ( " ) " ) ;
}
}
virtual void visit ( AstReplicate * nodep , AstNUser * ) {
if ( nodep - > lhsp ( ) - > widthMin ( ) = = 1 & & ! nodep - > isWide ( ) ) {
if ( ( ( int ) nodep - > rhsp ( ) - > castConst ( ) - > asInt ( )
* nodep - > lhsp ( ) - > widthMin ( ) ) ! = nodep - > widthMin ( ) )
nodep - > v3fatalSrc ( " Replicate non-constant or width miscomputed " ) ;
puts ( " VL_REPLICATE_ " ) ;
emitIQW ( nodep ) ;
puts ( " OI( " ) ;
puts ( cvtToStr ( nodep - > widthMin ( ) ) ) ;
if ( nodep - > lhsp ( ) ) { puts ( " , " + cvtToStr ( nodep - > lhsp ( ) - > widthMin ( ) ) ) ; }
if ( nodep - > rhsp ( ) ) { puts ( " , " + cvtToStr ( nodep - > rhsp ( ) - > widthMin ( ) ) ) ; }
puts ( " , " ) ;
} else {
emitOpName ( nodep , nodep - > emitOperator ( ) ) ;
}
nodep - > lhsp ( ) - > iterateAndNext ( * this ) ; puts ( " , " ) ;
nodep - > rhsp ( ) - > iterateAndNext ( * this ) ; puts ( " ) " ) ;
}
virtual void visit ( AstArraySel * nodep , AstNUser * ) {
nodep - > fromp ( ) - > iterateAndNext ( * this ) ; putbs ( " [ " ) ;
nodep - > bitp ( ) - > iterateAndNext ( * this ) ; puts ( " ] " ) ;
}
virtual void visit ( AstWordSel * nodep , AstNUser * ) {
nodep - > fromp ( ) - > iterateAndNext ( * this ) ; puts ( " [ " ) ; // Not putbs, as usually it's a small constant next
nodep - > bitp ( ) - > iterateAndNext ( * this ) ; puts ( " ] " ) ;
}
// Terminals
virtual void visit ( AstVarRef * nodep , AstNUser * ) {
puts ( nodep - > hiername ( ) ) ;
puts ( nodep - > varp ( ) - > name ( ) ) ;
}
void emitConstant ( AstConst * nodep , AstVarRef * assigntop , const string & assignString ) {
// Put out constant set to the specified variable, or given variable in a string
if ( nodep - > num ( ) . isFourState ( ) ) {
nodep - > v3error ( " Unsupported: 4-state numbers in this context " ) ;
} else if ( nodep - > isWide ( ) ) {
putbs ( " VL_CONST_W_ " ) ;
puts ( cvtToStr ( VL_WORDS_I ( nodep - > num ( ) . minWidth ( ) ) ) ) ;
puts ( " X( " ) ;
puts ( cvtToStr ( nodep - > widthMin ( ) ) ) ;
puts ( " , " ) ;
if ( ! assigntop ) {
puts ( assignString ) ;
} else if ( assigntop - > castVarRef ( ) ) {
puts ( assigntop - > hiername ( ) ) ;
puts ( assigntop - > varp ( ) - > name ( ) ) ;
} else {
assigntop - > iterateAndNext ( * this ) ;
}
for ( int word = VL_WORDS_I ( nodep - > num ( ) . minWidth ( ) ) - 1 ; word > 0 ; word - - ) {
ofp ( ) - > printf ( " ,0x%08x " , nodep - > num ( ) . dataWord ( word ) ) ;
}
ofp ( ) - > printf ( " ,0x%08x) " , nodep - > num ( ) . dataWord ( 0 ) ) ;
} else if ( nodep - > isQuad ( ) ) {
vluint64_t num = nodep - > asQuad ( ) ;
if ( num < 10 ) ofp ( ) - > printf ( " VL_ULL(%lld) " , ( long long ) num ) ;
else ofp ( ) - > printf ( " VL_ULL(0x%llx) " , ( long long ) num ) ;
} else {
uint32_t num = nodep - > asInt ( ) ;
if ( num < 10 ) puts ( cvtToStr ( num ) ) ;
else ofp ( ) - > printf ( " 0x%x " , num ) ;
//Unneeded-Causes %lx format warnings:
// if (!nodep->num().isSigned() && (num & (1UL<<31))) puts("U");
}
}
void emitSetVarConstant ( const string & assignString , AstConst * constp ) {
if ( ! constp - > isWide ( ) ) {
puts ( assignString ) ;
puts ( " = " ) ;
}
emitConstant ( constp , NULL , assignString ) ;
puts ( " ; \n " ) ;
}
virtual void visit ( AstConst * nodep , AstNUser * ) {
if ( nodep - > isWide ( ) ) {
if ( ! m_wideTempRefp ) nodep - > v3fatalSrc ( " Wide Constant w/ no temp " ) ;
emitConstant ( nodep , m_wideTempRefp , " " ) ;
m_wideTempRefp = NULL ; // We used it, barf if set it a second time
} else {
emitConstant ( nodep , NULL , " " ) ;
}
}
// Just iterate
virtual void visit ( AstTopScope * nodep , AstNUser * ) {
nodep - > iterateChildren ( * this ) ;
}
virtual void visit ( AstScope * nodep , AstNUser * ) {
nodep - > iterateChildren ( * this ) ;
}
// NOPs
virtual void visit ( AstPragma * , AstNUser * ) { }
virtual void visit ( AstCell * , AstNUser * ) { } // Handled outside the Visit class
virtual void visit ( AstVar * , AstNUser * ) { } // Handled outside the Visit class
virtual void visit ( AstNodeText * , AstNUser * ) { } // Handled outside the Visit class
virtual void visit ( AstTraceDecl * , AstNUser * ) { } // Handled outside the Visit class
virtual void visit ( AstTraceInc * , AstNUser * ) { } // Handled outside the Visit class
// Default
virtual void visit ( AstNode * nodep , AstNUser * ) {
puts ( ( string ) " \n ???? // " + nodep - > typeName ( ) + " \n " ) ;
nodep - > iterateChildren ( * this ) ;
nodep - > v3fatalSrc ( " Unknown node type reached emitter: " < < nodep - > typeName ( ) ) ;
}
public :
EmitCStmts ( ) {
m_suppressSemi = false ;
m_wideTempRefp = NULL ;
}
virtual ~ EmitCStmts ( ) { }
} ;
//######################################################################
// Internal EmitC implementation
class EmitCImp : EmitCStmts {
// MEMBERS
AstModule * m_modp ;
vector < AstChangeDet * > m_blkChangeDetVec ; // All encountered changes in block
bool m_slow ; // Creating __Slow file
bool m_fast ; // Creating non __Slow file (or both)
int m_splitSize ; // # of cfunc nodes placed into output file
int m_splitFilenum ; // File number being created, 0 = primary
//---------------------------------------
// METHODS
void doubleOrDetect ( AstChangeDet * changep , bool & gotOne ) {
static int addDoubleOr = 10 ; // Determined experimentally as best
if ( ! changep - > rhsp ( ) ) {
if ( ! gotOne ) gotOne = true ;
else puts ( " | " ) ;
changep - > lhsp ( ) - > iterateAndNext ( * this ) ;
}
else {
AstVarRef * lhsp = changep - > lhsp ( ) - > castVarRef ( ) ;
AstVarRef * rhsp = changep - > rhsp ( ) - > castVarRef ( ) ;
if ( ! lhsp ) changep - > v3fatalSrc ( " Not ref? " ) ;
if ( ! rhsp ) changep - > v3fatalSrc ( " Not ref? " ) ;
for ( int word = 0 ; word < changep - > lhsp ( ) - > widthWords ( ) ; word + + ) {
if ( ! gotOne ) {
gotOne = true ;
addDoubleOr = 10 ; // Determined experimentally as best
puts ( " ( " ) ;
} else if ( - - addDoubleOr = = 0 ) {
puts ( " || ( " ) ;
addDoubleOr = 10 ;
} else {
puts ( " | ( " ) ;
}
changep - > lhsp ( ) - > iterateAndNext ( * this ) ;
if ( changep - > isWide ( ) ) puts ( " [ " + cvtToStr ( word ) + " ] " ) ;
puts ( " ^ " ) ;
changep - > rhsp ( ) - > iterateAndNext ( * this ) ;
if ( changep - > isWide ( ) ) puts ( " [ " + cvtToStr ( word ) + " ] " ) ;
puts ( " ) " ) ;
}
}
}
V3OutCFile * newOutCFile ( AstModule * modp , bool slow , bool source , int filenum = 0 ) {
string filenameNoExt = v3Global . opt . makeDir ( ) + " / " + modClassName ( modp ) ;
if ( filenum ) filenameNoExt + = " __ " + cvtToStr ( filenum ) ;
filenameNoExt + = ( slow ? " __Slow " : " " ) ;
V3OutCFile * ofp = NULL ;
if ( optSystemPerl ( ) ) {
string filename = filenameNoExt + " .sp " ;
newCFile ( filename , slow , source ) ;
ofp = new V3OutSpFile ( filename ) ;
}
else if ( optSystemC ( ) ) {
string filename = filenameNoExt + ( source ? " .cpp " : " .h " ) ;
newCFile ( filename , slow , source ) ;
ofp = new V3OutScFile ( filename ) ;
}
else {
string filename = filenameNoExt + ( source ? " .cpp " : " .h " ) ;
newCFile ( filename , slow , source ) ;
ofp = new V3OutCFile ( filename ) ;
}
ofp - > putsHeader ( ) ;
return ofp ;
}
//---------------------------------------
// VISITORS
virtual void visit ( AstCFunc * nodep , AstNUser * ) {
if ( nodep - > funcType ( ) = = AstCFuncType : : TRACE_INIT
| | nodep - > funcType ( ) = = AstCFuncType : : TRACE_FULL
| | nodep - > funcType ( ) = = AstCFuncType : : TRACE_CHANGE ) {
return ; // Handled specially
}
if ( ! ( nodep - > slow ( ) ? m_slow : m_fast ) ) return ;
m_blkChangeDetVec . clear ( ) ;
m_splitSize + = EmitCBaseCounterVisitor ( nodep ) . count ( ) ;
puts ( " \n " ) ;
puts ( nodep - > rtnTypeVoid ( ) ) ; puts ( " " ) ;
puts ( modClassName ( m_modp ) + " :: " + nodep - > name ( )
+ " ( " + cFuncArgs ( nodep ) + " ) { \n " ) ;
2006-08-31 00:00:55 +02:00
puts ( " VL_DEBUG_IF(cout<< \" " ) ;
2006-08-26 13:35:28 +02:00
for ( int i = 0 ; i < m_modp - > level ( ) ; i + + ) { puts ( " " ) ; }
puts ( modClassName ( m_modp ) + " :: " + nodep - > name ( )
2006-08-31 00:00:55 +02:00
+ " \" <<endl; ); \n " ) ;
2006-08-26 13:35:28 +02:00
2006-08-30 23:07:55 +02:00
if ( nodep - > symProlog ( ) ) puts ( EmitCBaseVisitor : : symTopAssign ( ) + " \n " ) ;
2006-08-26 13:35:28 +02:00
if ( nodep - > initsp ( ) ) puts ( " // Variables \n " ) ;
2006-08-29 02:58:48 +02:00
ofp ( ) - > putAlign ( V3OutFile : : AL_AUTO , 4 ) ;
2006-08-26 13:35:28 +02:00
for ( AstNode * subnodep = nodep - > argsp ( ) ; subnodep ; subnodep = subnodep - > nextp ( ) ) {
if ( AstVar * varp = subnodep - > castVar ( ) ) {
if ( varp - > isFuncReturn ( ) ) emitVarDecl ( varp , " " ) ;
}
}
emitVarList ( nodep - > initsp ( ) , EVL_ALL , " " ) ;
2006-08-29 02:58:48 +02:00
ofp ( ) - > putAlign ( V3OutFile : : AL_AUTO , 4 ) ;
2006-08-26 13:35:28 +02:00
emitVarList ( nodep - > stmtsp ( ) , EVL_ALL , " " ) ;
2006-08-29 02:58:48 +02:00
ofp ( ) - > putAlign ( V3OutFile : : AL_AUTO , 4 ) ;
2006-08-26 13:35:28 +02:00
nodep - > initsp ( ) - > iterateAndNext ( * this ) ;
if ( nodep - > stmtsp ( ) ) puts ( " // Body \n " ) ;
nodep - > stmtsp ( ) - > iterateAndNext ( * this ) ;
# ifndef NEW_ORDERING
if ( ! m_blkChangeDetVec . empty ( ) ) emitChangeDet ( ) ;
# endif
if ( nodep - > finalsp ( ) ) puts ( " // Final \n " ) ;
nodep - > finalsp ( ) - > iterateAndNext ( * this ) ;
//
if ( ! m_blkChangeDetVec . empty ( ) ) puts ( " return __req; \n " ) ;
// puts("__Vm_activity = true;\n");
puts ( " } \n " ) ;
}
void emitChangeDet ( ) {
puts ( " // Change detection \n " ) ;
puts ( " IData __req = false; // Logically a bool \n " ) ; // But not because it results in faster code
bool gotOne = false ;
for ( vector < AstChangeDet * > : : iterator it = m_blkChangeDetVec . begin ( ) ;
it ! = m_blkChangeDetVec . end ( ) ; + + it ) {
AstChangeDet * changep = * it ;
if ( changep - > lhsp ( ) ) {
if ( ! gotOne ) { // Not a clocked block
puts ( " __req |= ( " ) ;
}
else puts ( " \n " ) ;
doubleOrDetect ( changep , gotOne ) ;
}
}
if ( gotOne ) {
puts ( " ); \n " ) ;
//puts("VL_DEBUG_IF( if (__req) cout<<\"\tCLOCKREQ );");
}
}
virtual void visit ( AstChangeDet * nodep , AstNUser * ) {
m_blkChangeDetVec . push_back ( nodep ) ;
}
//---------------------------------------
// ACCESSORS
// METHODS
// Low level
void emitVarResets ( AstModule * modp ) ;
void emitCellCtors ( AstModule * modp ) ;
void emitSensitives ( ) ;
// Medium level
2006-08-30 19:27:53 +02:00
void emitCtorImp ( AstModule * modp ) ;
void emitConfigureImp ( AstModule * modp ) ;
2006-08-26 13:35:28 +02:00
void emitCoverageDecl ( AstModule * modp ) ;
2006-08-30 03:14:29 +02:00
void emitCoverageImp ( AstModule * modp ) ;
2006-08-30 19:27:53 +02:00
void emitDestructorImp ( AstModule * modp ) ;
2006-08-26 13:35:28 +02:00
void emitTextSection ( AstType type ) ;
void emitIntFuncDecls ( AstModule * modp ) ;
// High level
void emitImp ( AstModule * modp ) ;
void emitImpBottom ( AstModule * modp ) ;
void emitStaticDecl ( AstModule * modp ) ;
void emitWrapEval ( AstModule * modp ) ;
void emitInt ( AstModule * modp ) ;
void writeMakefile ( string filename ) ;
public :
EmitCImp ( ) {
m_modp = NULL ;
m_splitSize = 0 ;
m_splitFilenum = 0 ;
}
virtual ~ EmitCImp ( ) { }
void main ( AstModule * modp , bool slow , bool fast ) ;
void mainDoFunc ( AstCFunc * nodep ) {
nodep - > accept ( * this ) ;
}
int splitSize ( ) { return m_splitSize ; }
} ;
//######################################################################
// Internal EmitCStmts
void EmitCStmts : : emitVarDecl ( AstVar * nodep , const string & prefixIfImp ) {
if ( nodep - > isIO ( ) ) {
if ( nodep - > isSc ( ) ) {
m_ctorVarsVec . push_back ( nodep ) ;
2006-08-29 02:58:48 +02:00
ofp ( ) - > putAlign ( nodep - > isStatic ( ) , 4 ) ; // sc stuff is a structure, so bigger alignment
2006-08-26 13:35:28 +02:00
if ( nodep - > attrScClocked ( ) & & nodep - > isInput ( ) ) {
puts ( " sc_in_clk \t " ) ;
} else {
if ( nodep - > isTristate ( ) ) puts ( " sc_inout< " ) ;
else if ( nodep - > isInput ( ) ) puts ( " sc_in< " ) ;
else if ( nodep - > isOutput ( ) ) puts ( " sc_out< " ) ;
else nodep - > v3fatalSrc ( " Unknown type " ) ;
puts ( nodep - > cType ( ) ) ;
puts ( " > \t " ) ;
}
puts ( nodep - > name ( ) ) ;
puts ( " ; \n " ) ;
} else { // C++ signals
2006-08-29 02:58:48 +02:00
ofp ( ) - > putAlign ( nodep - > isStatic ( ) , nodep - > widthAlignBytes ( ) ) ;
2006-08-26 13:35:28 +02:00
if ( nodep - > isTristate ( ) ) puts ( " VL_INOUT " ) ;
else if ( nodep - > isInput ( ) ) puts ( " VL_IN " ) ;
else if ( nodep - > isOutput ( ) ) puts ( " VL_OUT " ) ;
else nodep - > v3fatalSrc ( " Unknown type " ) ;
if ( nodep - > isQuad ( ) ) puts ( " 64 " ) ;
else if ( nodep - > widthMin ( ) < = 8 ) puts ( " 8 " ) ;
else if ( nodep - > widthMin ( ) < = 16 ) puts ( " 16 " ) ;
if ( ! nodep - > isWide ( ) )
puts ( " ( " + nodep - > name ( )
+ " , " + cvtToStr ( nodep - > msb ( ) )
+ " , " + cvtToStr ( nodep - > lsb ( ) ) ) ;
else puts ( " W( " + nodep - > name ( )
+ " , " + cvtToStr ( nodep - > msb ( ) )
+ " , " + cvtToStr ( nodep - > lsb ( ) )
+ " , " + cvtToStr ( nodep - > widthWords ( ) ) ) ;
puts ( " ); \n " ) ;
}
} else {
// Arrays need a small alignment, but may need different padding after.
// For example three VL_SIG8's needs alignment 1 but size 3.
2006-08-29 02:58:48 +02:00
ofp ( ) - > putAlign ( nodep - > isStatic ( ) , nodep - > widthAlignBytes ( ) , nodep - > arrayElements ( ) * nodep - > widthAlignBytes ( ) ) ;
if ( nodep - > isStatic ( ) & & prefixIfImp = = " " ) puts ( " static " ) ;
2006-08-29 14:01:02 +02:00
if ( nodep - > isStatic ( ) ) puts ( " VL_ST_ " ) ; else puts ( " VL_ " ) ;
2006-08-26 13:35:28 +02:00
if ( nodep - > widthMin ( ) < = 8 ) {
2006-08-29 14:01:02 +02:00
puts ( " SIG8( " ) ;
2006-08-26 13:35:28 +02:00
} else if ( nodep - > widthMin ( ) < = 16 ) {
2006-08-29 14:01:02 +02:00
puts ( " SIG16( " ) ;
2006-08-26 13:35:28 +02:00
} else if ( nodep - > isQuad ( ) ) {
2006-08-29 14:01:02 +02:00
puts ( " SIG64( " ) ;
2006-08-26 13:35:28 +02:00
} else if ( ! nodep - > isWide ( ) ) {
2006-08-29 14:01:02 +02:00
puts ( " SIG( " ) ;
2006-08-26 13:35:28 +02:00
} else {
2006-08-29 14:01:02 +02:00
puts ( " SIGW( " ) ;
2006-08-26 13:35:28 +02:00
}
if ( prefixIfImp ! = " " ) { puts ( prefixIfImp ) ; puts ( " :: " ) ; }
puts ( nodep - > name ( ) ) ;
for ( AstRange * arrayp = nodep - > arraysp ( ) ; arrayp ; arrayp = arrayp - > nextp ( ) - > castRange ( ) ) {
puts ( " [ " + cvtToStr ( arrayp - > elementsConst ( ) ) + " ] " ) ;
}
puts ( " , " + cvtToStr ( nodep - > msb ( ) ) + " , " + cvtToStr ( nodep - > lsb ( ) ) ) ;
if ( nodep - > isWide ( ) ) puts ( " , " + cvtToStr ( nodep - > widthWords ( ) ) ) ;
puts ( " ); \n " ) ;
}
}
void EmitCStmts : : emitVarCtors ( ) {
ofp ( ) - > indentInc ( ) ;
bool first = true ;
for ( vector < AstVar * > : : iterator it = m_ctorVarsVec . begin ( ) ; it ! = m_ctorVarsVec . end ( ) ; + + it ) {
if ( first ) {
first = false ;
puts ( " \n " ) ;
puts ( " #if (SYSTEMC_VERSION>20011000) \n " ) ; // SystemC 2.0.1 and newer
puts ( " : " ) ;
}
else puts ( " , " ) ;
if ( ofp ( ) - > exceededWidth ( ) ) puts ( " \n " ) ;
puts ( ( * it ) - > name ( ) ) ; puts ( " ( \" " ) ;
puts ( ( * it ) - > name ( ) ) ; puts ( " \" ) " ) ;
}
if ( ! first ) puts ( " \n #endif \n " ) ;
ofp ( ) - > indentDec ( ) ;
}
bool EmitCStmts : : emitSimpleOk ( AstNodeMath * nodep ) {
// Can we put out a simple (A + B) instead of VL_ADD_III(A,B)?
if ( nodep - > emitSimpleOperator ( ) = = " " ) return false ;
if ( nodep - > isWide ( ) ) return false ;
if ( nodep - > op1p ( ) ) { if ( nodep - > op1p ( ) - > isWide ( ) ) return false ; }
if ( nodep - > op2p ( ) ) { if ( nodep - > op2p ( ) - > isWide ( ) ) return false ; }
if ( nodep - > op3p ( ) ) { if ( nodep - > op3p ( ) - > isWide ( ) ) return false ; }
return true ;
}
void EmitCStmts : : emitOpName ( AstNode * nodep , const string & opname ) {
putbs ( opname + " _ " ) ;
if ( nodep - > emitWordForm ( ) ) {
emitIQW ( nodep - > op1p ( ) ) ;
puts ( " ( " ) ;
if ( nodep - > op1p ( ) - > isWide ( ) ) {
puts ( cvtToStr ( nodep - > op1p ( ) - > widthWords ( ) ) ) ;
puts ( " , " ) ;
}
} else {
emitIQW ( nodep ) ;
if ( nodep - > op1p ( ) ) { emitIQW ( nodep - > op1p ( ) ) ; }
if ( nodep - > op2p ( ) ) { emitIQW ( nodep - > op2p ( ) ) ; }
if ( nodep - > op3p ( ) ) { emitIQW ( nodep - > op3p ( ) ) ; }
puts ( " ( " ) ;
puts ( cvtToStr ( nodep - > widthMin ( ) ) ) ;
if ( nodep - > op1p ( ) ) { puts ( " , " + cvtToStr ( nodep - > op1p ( ) - > widthMin ( ) ) ) ; }
if ( nodep - > op2p ( ) ) { puts ( " , " + cvtToStr ( nodep - > op2p ( ) - > widthMin ( ) ) ) ; }
if ( nodep - > op3p ( ) ) { puts ( " , " + cvtToStr ( nodep - > op3p ( ) - > widthMin ( ) ) ) ; }
if ( nodep - > op1p ( ) | | nodep - > isWide ( ) ) puts ( " , " ) ;
}
if ( nodep - > isWide ( ) ) {
if ( ! m_wideTempRefp ) nodep - > v3fatalSrc ( " Wide Op w/ no temp, perhaps missing op in V3EmitC? " ) ;
puts ( m_wideTempRefp - > hiername ( ) ) ;
puts ( m_wideTempRefp - > varp ( ) - > name ( ) ) ;
m_wideTempRefp = NULL ;
if ( nodep - > op1p ( ) ) puts ( " , " ) ;
}
}
//----------------------------------------------------------------------
// Mid level - VISITS
// We only do one display at once, so can just use static state
struct EmitDispState {
bool m_wide ; // Put out a wide func that needs string buffer
string m_format ; // "%s" and text from user
vector < AstNode * > m_argsp ; // Each argument to be printed
vector < string > m_argsFunc ; // Function before each argument to be printed
EmitDispState ( ) { clear ( ) ; }
void clear ( ) {
m_wide = false ;
m_format = " " ;
m_argsp . clear ( ) ;
m_argsFunc . clear ( ) ;
}
void pushFormat ( const string & fmt ) { m_format + = fmt ; }
void pushFormat ( char fmt ) { m_format + = fmt ; }
void pushArg ( AstNode * nodep , const string & func ) {
m_argsp . push_back ( nodep ) ; m_argsFunc . push_back ( func ) ;
}
} emitDispState ;
void EmitCStmts : : displayEmit ( AstDisplay * nodep ) {
if ( emitDispState . m_format ! = " " ) {
// Format
if ( nodep - > filep ( ) ) {
puts ( " if ( " ) ;
nodep - > filep ( ) - > iterate ( * this ) ; // Check if closed, to avoid core dump
puts ( " ) fprintf(VL_CVT_Q_FP( " ) ;
nodep - > filep ( ) - > iterate ( * this ) ;
puts ( " ), \" " ) ;
} else {
puts ( " VL_PRINTF( \" " ) ;
}
ofp ( ) - > putsNoTracking ( emitDispState . m_format ) ;
puts ( " \" " ) ;
// Arguments
for ( unsigned i = 0 ; i < emitDispState . m_argsp . size ( ) ; i + + ) {
puts ( " , " ) ;
AstNode * argp = emitDispState . m_argsp [ i ] ;
string func = emitDispState . m_argsFunc [ i ] ;
ofp ( ) - > indentInc ( ) ;
ofp ( ) - > putbs ( " " ) ;
if ( func ! = " " ) puts ( func ) ;
if ( argp ) argp - > iterate ( * this ) ;
if ( func ! = " " ) puts ( " ) " ) ;
ofp ( ) - > indentDec ( ) ;
}
// End
puts ( " ); \n " ) ;
// Prep for next
emitDispState . clear ( ) ;
}
}
string EmitCStmts : : displayFormat ( AstNode * widthNodep , string in ,
char fmtLetter , bool padZero , bool reallyString ) {
if ( fmtLetter = = ' s ' ) padZero = false ;
if ( widthNodep & & widthNodep - > isWide ( )
& & ( fmtLetter = = ' d ' | | fmtLetter = = ' u ' ) ) {
widthNodep - > v3error ( " Unsupported: $display of dec format of > 64 bit results (use hex format instead) " ) ;
}
if ( widthNodep & & widthNodep - > widthMin ( ) > 8 & & fmtLetter = = ' c ' ) {
widthNodep - > v3error ( " $display of char format of > 8 bit result " ) ;
}
string fmt ;
if ( in = = " " ) {
// Size naturally
if ( widthNodep = = NULL ) fmt = " " ; // Out of args, will get error
if ( fmtLetter = = ' u ' | | fmtLetter = = ' d ' ) { // Decimal. Spec says leading spaces, not zeros
double mantissabits = widthNodep - > widthMin ( ) - ( ( fmtLetter = = ' d ' ) ? 1 : 0 ) ;
double maxval = pow ( 2.0 , mantissabits ) ;
double dchars = log10 ( maxval ) + 1.0 ;
if ( fmtLetter = = ' d ' ) dchars + + ; // space for sign
int nchars = int ( dchars ) ;
fmt = cvtToStr ( nchars ) ;
} else if ( fmtLetter ! = ' s ' & & fmtLetter ! = ' c ' ) { // Strings/chars don't get padding
int bitsPerChar = ( fmtLetter = = ' b ' ? 1 : fmtLetter = = ' o ' ? 3 : 4 ) ;
int nchars = ( widthNodep - > widthMin ( ) + bitsPerChar - 1 ) / bitsPerChar ;
if ( padZero ) fmt = ( string ) ( " 0 " ) + cvtToStr ( nchars ) ;
else fmt = cvtToStr ( nchars ) ;
}
} else if ( in = = " 0 " ) {
fmt = " " ; // No width
} else {
fmt = in ;
}
if ( widthNodep - > isQuad ( ) & & fmtLetter ! = ' c ' & & fmtLetter ! = ' s ' & & ! reallyString ) fmt + = " ll " ;
return fmt ;
}
void EmitCStmts : : displayArg ( AstDisplay * dispp , AstNode * * elistp , string fmt , char fmtLetter ) {
// Print display argument, edits elistp
if ( ! * elistp ) {
dispp - > v3error ( " Missing arguments for $display format " ) ;
return ;
}
if ( ( * elistp ) - > widthMin ( ) > VL_VALUE_STRING_MAX_WIDTH ) {
dispp - > v3error ( " Exceeded limit of 1024 bits for any display arguments " ) ;
}
if ( ( * elistp ) - > isWide ( ) // Have to use our own function for wide,
| | fmtLetter = = ' s ' // ... Verilog strings
| | fmtLetter = = ' b ' // ... binary, no printf %b in C
| | fmtLetter = = ' d ' ) { // ... Signed decimal
// We use a single static string, so must only have one call per VL_PRINT
if ( emitDispState . m_wide ) { displayEmit ( dispp ) ; }
emitDispState . m_wide = true ;
string nfmt = displayFormat ( * elistp , fmt , fmtLetter , false , true ) ;
string pfmt = " % " + nfmt + " s " ;
string func = " VL_VALUE_FORMATTED_ " ;
func + = ( ( * elistp ) - > isWide ( ) ) ? " W( " : ( ( * elistp ) - > isQuad ( ) ) ? " Q( " : " I( " ;
func + = ( cvtToStr ( ( * elistp ) - > widthMin ( ) )
+ " ,' " + fmtLetter + " ' "
+ " , " + ( fmt = = " 0 " ? " true " : " false " ) + " , " ) ;
emitDispState . pushFormat ( pfmt ) ;
emitDispState . pushArg ( * elistp , func ) ;
} else {
string nfmt = displayFormat ( * elistp , fmt , fmtLetter , true , false ) ;
string pfmt = " % " + nfmt + fmtLetter ;
emitDispState . pushFormat ( pfmt ) ;
emitDispState . pushArg ( * elistp , " " ) ;
}
// Next parameter
* elistp = ( * elistp ) - > nextp ( ) ;
}
void EmitCStmts : : visit ( AstDisplay * nodep , AstNUser * ) {
string vformat = nodep - > text ( ) ;
bool addNewline = ( nodep - > newline ( ) = = ' \n ' ) ;
AstNode * elistp = nodep - > exprsp ( ) ;
// Convert Verilog display to C printf formats
// "%0t" becomes "%d"
emitDispState . clear ( ) ;
string fmt = " " ;
string : : iterator pos = vformat . begin ( ) ;
if ( * pos = = ' " ' ) pos + + ;
bool inPct = false ;
for ( ; pos ! = vformat . end ( ) ; + + pos ) {
if ( pos [ 0 ] = = ' " ' & & ( pos + 1 ) = = vformat . end ( ) ) break ;
if ( inPct & & pos [ 0 ] = = ' % ' ) {
emitDispState . pushFormat ( " %% " ) ; // We're printf'ing it, so need to quote the %
inPct = false ;
} else if ( pos [ 0 ] = = ' % ' ) {
inPct = true ;
fmt = " " ;
} else if ( ! inPct ) { // Normal text
//char text[2]; text[0]=*pos; text[1]='\0';
emitDispState . pushFormat ( * pos ) ;
} else { // Format character
if ( isdigit ( pos [ 0 ] ) ) {
// Digits, like %5d, etc.
fmt + = pos [ 0 ] ;
} else {
inPct = false ;
switch ( tolower ( pos [ 0 ] ) ) {
// Special codes
case ' ~ ' : displayArg ( nodep , & elistp , fmt , ' d ' ) ; break ; // Signed decimal
// Spec: h d o b c l
case ' b ' : displayArg ( nodep , & elistp , fmt , ' b ' ) ; break ;
case ' c ' : displayArg ( nodep , & elistp , fmt , ' c ' ) ; break ;
case ' d ' : displayArg ( nodep , & elistp , fmt , ' u ' ) ; break ; // Unsigned decimal
case ' o ' : displayArg ( nodep , & elistp , fmt , ' o ' ) ; break ;
case ' h ' :
case ' x ' : displayArg ( nodep , & elistp , fmt , ' x ' ) ; break ;
case ' s ' : displayArg ( nodep , & elistp , fmt , ' s ' ) ; break ;
case ' t ' : displayArg ( nodep , & elistp , fmt , ' u ' ) ; break ;
case ' m ' : {
emitDispState . pushFormat ( " %s " ) ;
2006-08-31 00:00:55 +02:00
emitDispState . pushArg ( NULL , " vlSymsp->name( " ) ;
2006-08-26 13:35:28 +02:00
for ( AstText * textp = nodep - > scopeTextp ( ) ; textp ; textp = textp - > nextp ( ) - > castText ( ) ) {
emitDispState . pushFormat ( textp - > text ( ) ) ;
}
break ;
}
case ' u ' :
case ' z ' :
case ' l ' :
case ' v ' :
nodep - > v3error ( " Unsupported: $display format code: % " < < pos [ 0 ] ) ;
break ;
default :
nodep - > v3error ( " Unknown $display format code: % " < < pos [ 0 ] ) ;
break ;
}
}
}
}
if ( elistp ! = NULL ) {
nodep - > v3error ( " Extra arguments for $display format \n " ) ;
}
if ( addNewline ) emitDispState . pushFormat ( " \\ n " ) ;
displayEmit ( nodep ) ;
}
//######################################################################
// Internal EmitC
void EmitCImp : : emitVarResets ( AstModule * modp ) {
puts ( " // Reset internal values \n " ) ;
if ( modp - > isTop ( ) ) {
2006-08-29 02:27:04 +02:00
if ( v3Global . opt . inhibitSim ( ) ) puts ( " __Vm_inhibitSim = false; \n " ) ;
2006-08-26 13:35:28 +02:00
puts ( " \n " ) ;
}
puts ( " // Reset structure values \n " ) ;
for ( AstNode * nodep = modp - > stmtsp ( ) ; nodep ; nodep = nodep - > nextp ( ) ) {
if ( AstVar * varp = nodep - > castVar ( ) ) {
if ( varp - > isIO ( ) & & modp - > isTop ( ) & & optSystemC ( ) ) {
// System C top I/O doesn't need loading, as the lower level subinst code does it.
}
else if ( varp - > isParam ( ) ) {
if ( ! varp - > hasSimpleInit ( ) ) nodep - > v3fatalSrc ( " No init for a param? " ) ;
//puts("// parameter "+varp->name()+" = "+varp->initp()->name()+"\n");
}
else if ( AstInitArray * initarp = varp - > initp ( ) - > castInitArray ( ) ) {
AstConst * constsp = initarp - > initsp ( ) - > castConst ( ) ;
if ( ! varp - > arraysp ( ) ) varp - > v3fatalSrc ( " InitArray under non-arrayed var " ) ;
for ( int i = 0 ; i < varp - > arraysp ( ) - > elementsConst ( ) ; i + + ) {
if ( ! constsp ) initarp - > v3fatalSrc ( " Not enough values in array initalizement " ) ;
emitSetVarConstant ( varp - > name ( ) + " [ " + cvtToStr ( i ) + " ] " , constsp ) ;
constsp = constsp - > nextp ( ) - > castConst ( ) ;
}
}
else {
int vects = 0 ;
for ( AstRange * arrayp = varp - > arraysp ( ) ; arrayp ; arrayp = arrayp - > nextp ( ) - > castRange ( ) ) {
int vecnum = vects + + ;
if ( arrayp - > msbConst ( ) < arrayp - > lsbConst ( ) ) varp - > v3fatalSrc ( " Should have swapped msb & lsb earlier. " ) ;
string ivar = string ( " __Vi " ) + cvtToStr ( vecnum ) ;
// MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block
puts ( " { int __Vi " + cvtToStr ( vecnum ) + " = " + cvtToStr ( 0 ) + " ; " ) ;
puts ( " for (; " + ivar + " < " + cvtToStr ( arrayp - > elementsConst ( ) ) ) ;
puts ( " ; ++ " + ivar + " ) { \n " ) ;
}
bool zeroit = ( varp - > attrFileDescr ( ) // Zero it out, so we don't core dump if never call $fopen
| | ( varp - > name ( ) . c_str ( ) [ 0 ] = = ' _ ' & & v3Global . opt . underlineZero ( ) ) ) ;
if ( varp - > isWide ( ) ) {
// DOCUMENT: We randomize everything. If the user wants a _var to be zero,
// there should be a initial statement. (Different from verilator2.)
if ( zeroit ) puts ( " VL_ZERO_RESET_W( " ) ;
else puts ( " VL_RAND_RESET_W( " ) ;
puts ( cvtToStr ( varp - > widthMin ( ) ) ) ;
puts ( " , " ) ;
puts ( varp - > name ( ) ) ;
for ( int v = 0 ; v < vects ; + + v ) puts ( " [__Vi " + cvtToStr ( v ) + " ] " ) ;
puts ( " ); \n " ) ;
} else {
puts ( varp - > name ( ) ) ;
for ( int v = 0 ; v < vects ; + + v ) puts ( " [__Vi " + cvtToStr ( v ) + " ] " ) ;
if ( zeroit ) {
puts ( " = 0; \n " ) ;
} else {
puts ( " = VL_RAND_RESET_ " ) ;
emitIQW ( varp ) ;
puts ( " ( " ) ;
puts ( cvtToStr ( varp - > widthMin ( ) ) ) ;
puts ( " ); \n " ) ;
}
}
for ( int v = 0 ; v < vects ; + + v ) puts ( " }} \n " ) ;
}
}
}
}
void EmitCImp : : emitCoverageDecl ( AstModule * modp ) {
m_coverIds . clear ( ) ;
for ( AstNode * nodep = modp - > stmtsp ( ) ; nodep ; nodep = nodep - > nextp ( ) ) {
if ( AstCoverDecl * declp = nodep - > castCoverDecl ( ) ) {
m_coverIds . remap ( declp ) ;
}
}
if ( m_coverIds . size ( ) ) {
ofp ( ) - > putsPrivate ( true ) ;
puts ( " // Coverage \n " ) ;
puts ( " SpZeroed<uint32_t> \t __Vcoverage[ " ) ; puts ( cvtToStr ( m_coverIds . size ( ) ) ) ; puts ( " ]; \n " ) ;
2006-08-29 02:58:48 +02:00
ofp ( ) - > putAlign ( V3OutFile : : AL_AUTO , sizeof ( uint32_t ) * m_coverIds . size ( ) ) ;
2006-08-30 03:14:29 +02:00
puts ( " void __vlCoverInsert(SpZeroed<uint32_t>* countp, const char* filename, int lineno, int column, \n " ) ;
puts ( " const char* hier, const char* type, const char* comment); \n " ) ;
}
}
2006-08-30 19:27:53 +02:00
void EmitCImp : : emitCtorImp ( AstModule * modp ) {
puts ( " \n " ) ;
if ( optSystemPerl ( ) & & modp - > isTop ( ) ) {
puts ( " SP_CTOR_IMP( " + modClassName ( modp ) + " ) " ) ;
} else if ( optSystemC ( ) & & modp - > isTop ( ) ) {
puts ( " VL_SC_CTOR_IMP( " + modClassName ( modp ) + " ) " ) ;
} else {
puts ( " VL_CTOR_IMP( " + modClassName ( modp ) + " ) " ) ;
}
emitVarCtors ( ) ;
puts ( " { \n " ) ;
emitCellCtors ( modp ) ;
emitSensitives ( ) ;
emitVarResets ( modp ) ;
emitTextSection ( AstType : : SCCTOR ) ;
if ( optSystemPerl ( ) ) puts ( " SP_AUTO_CTOR; \n " ) ;
puts ( " } \n " ) ;
}
void EmitCImp : : emitConfigureImp ( AstModule * modp ) {
puts ( " \n void " + modClassName ( modp ) + " ::__Vconfigure( " + symClassName ( ) + " * symsp) { \n " ) ;
puts ( " __VlSymsp = symsp; \n " ) ; // First, as later stuff needs it.
bool first = true ;
for ( AstNode * nodep = modp - > stmtsp ( ) ; nodep ; nodep = nodep - > nextp ( ) ) {
if ( nodep - > castCoverDecl ( ) ) {
if ( first ) {
first = false ;
puts ( " // Coverage Declarations \n " ) ;
}
nodep - > accept ( * this ) ;
}
}
puts ( " } \n " ) ;
}
2006-08-30 03:14:29 +02:00
void EmitCImp : : emitCoverageImp ( AstModule * modp ) {
if ( m_coverIds . size ( ) ) {
puts ( " \n // Coverage \n " ) ;
2006-08-26 13:35:28 +02:00
// Rather then putting out SP_COVER_INSERT calls directly, we do it via this function
// This gets around gcc slowness constructing all of the template arguments
2006-08-30 03:14:29 +02:00
puts ( " void " + modClassName ( m_modp ) + " ::__vlCoverInsert(SpZeroed<uint32_t>* countp, const char* filename, int lineno, int column, \n " ) ;
2006-08-26 13:35:28 +02:00
puts ( " const char* hier, const char* type, const char* comment) { \n " ) ;
puts ( " SP_COVER_INSERT(countp, " ) ;
puts ( " \" filename \" ,filename, " ) ;
puts ( " \" lineno \" ,lineno, " ) ;
puts ( " \" column \" ,column, \n " ) ;
2006-08-30 03:14:29 +02:00
//puts( "\"hier\",string(__VlSymsp->name())+hier,"); // Need to move hier into scopes and back out if do this
2006-08-26 13:35:28 +02:00
puts ( " \" hier \" ,string(name())+hier, " ) ;
puts ( " \" type \" ,type, " ) ;
puts ( " \" comment \" ,comment); \n " ) ;
puts ( " } \n " ) ;
}
}
2006-08-30 19:27:53 +02:00
void EmitCImp : : emitDestructorImp ( AstModule * modp ) {
puts ( " \n " ) ;
puts ( modClassName ( modp ) + " ::~ " + modClassName ( modp ) + " () { \n " ) ;
emitTextSection ( AstType : : SCDTOR ) ;
if ( modp - > isTop ( ) ) puts ( " delete __VlSymsp; __VlSymsp=NULL; \n " ) ;
puts ( " } \n " ) ;
}
2006-08-26 13:35:28 +02:00
void EmitCImp : : emitStaticDecl ( AstModule * modp ) {
// Need implementation here. Be careful of alignment code; needs to be uniquified
// with module name to avoid multiple symbols.
//emitVarList(modp->stmtsp(), EVL_ALL, modp->name());
}
void EmitCImp : : emitTextSection ( AstType type ) {
int last_line = - 999 ;
for ( AstNode * nodep = m_modp - > stmtsp ( ) ; nodep ! = NULL ; nodep = nodep - > nextp ( ) ) {
if ( AstNodeText * textp = nodep - > castNodeText ( ) ) {
if ( nodep - > type ( ) = = type ) {
if ( last_line ! = nodep - > fileline ( ) - > lineno ( ) ) {
if ( last_line < 0 ) {
puts ( " \n //*** Below code from `systemc in Verilog file \n " ) ;
}
ofp ( ) - > putsNoTracking ( " //#line " + cvtToStr ( nodep - > fileline ( ) - > lineno ( ) )
+ " \" " + nodep - > fileline ( ) - > filename ( ) + " \" \n " ) ;
last_line = nodep - > fileline ( ) - > lineno ( ) ;
}
ofp ( ) - > putsNoTracking ( textp - > text ( ) ) ;
last_line + + ;
}
}
}
if ( last_line > 0 ) {
puts ( " //*** Above code from `systemc in Verilog file \n \n " ) ;
}
}
void EmitCImp : : emitCellCtors ( AstModule * modp ) {
if ( modp - > isTop ( ) ) {
2006-08-30 03:14:29 +02:00
// Must be before other constructors, as __vlCoverInsert calls it
2006-08-30 23:07:55 +02:00
puts ( EmitCBaseVisitor : : symClassVar ( ) + " = __VlSymsp = new " + symClassName ( ) + " (this, name()); \n " ) ;
puts ( EmitCBaseVisitor : : symTopAssign ( ) + " \n " ) ;
2006-08-26 13:35:28 +02:00
}
for ( AstNode * nodep = modp - > stmtsp ( ) ; nodep ; nodep = nodep - > nextp ( ) ) {
if ( AstCell * cellp = nodep - > castCell ( ) ) {
puts ( " VL_CELL ( " + cellp - > name ( ) + " , " + modClassName ( cellp - > modp ( ) ) + " ); \n " ) ;
}
}
}
void EmitCImp : : emitSensitives ( ) {
// Create sensitivity list for when to evaluate the model.
// If C++ code, the user must call this routine themself.
if ( m_modp - > isTop ( ) & & optSystemC ( ) ) {
puts ( " // Sensitivities on all clocks and combo inputs \n " ) ;
puts ( " SC_METHOD(eval); \n " ) ;
for ( AstNode * nodep = m_modp - > stmtsp ( ) ; nodep ; nodep = nodep - > nextp ( ) ) {
if ( AstVar * varp = nodep - > castVar ( ) ) {
if ( varp - > isInput ( ) & & ( varp - > isScSensitive ( ) | | varp - > isUsedClock ( ) ) ) {
puts ( " sensitive( " + varp - > name ( ) + " ); \n " ) ;
}
}
}
puts ( " \n " ) ;
}
}
void EmitCImp : : emitWrapEval ( AstModule * modp ) {
puts ( " \n void " + modClassName ( modp ) + " ::eval() { \n " ) ;
2006-08-30 23:07:55 +02:00
puts ( EmitCBaseVisitor : : symClassVar ( ) + " = this->__VlSymsp; // Setup global symbol table \n " ) ;
puts ( EmitCBaseVisitor : : symTopAssign ( ) + " \n " ) ;
2006-08-26 13:35:28 +02:00
puts ( " // Initialize \n " ) ;
2006-08-30 23:07:55 +02:00
puts ( " if (VL_UNLIKELY(!vlSymsp->__Vm_didInit)) _eval_initial_loop(vlSymsp); \n " ) ;
2006-08-29 02:27:04 +02:00
if ( v3Global . opt . inhibitSim ( ) ) {
2006-08-30 23:07:55 +02:00
puts ( " if (VL_UNLIKELY(__Vm_inhibitSim)) return; \n " ) ;
2006-08-29 02:27:04 +02:00
}
2006-08-26 13:35:28 +02:00
puts ( " // Evaluate till stable \n " ) ;
puts ( " VL_DEBUG_IF(cout<< \" \\ n----TOP Evaluate " + modClassName ( modp ) + " ::eval \" <<endl; ); \n " ) ;
# ifndef NEW_ORDERING
puts ( " int __VclockLoop = 0; \n " ) ;
2006-08-30 23:07:55 +02:00
puts ( " IData __Vchange=1; \n " ) ;
puts ( " while (VL_LIKELY(__Vchange)) { \n " ) ;
2006-08-26 13:35:28 +02:00
puts ( " VL_DEBUG_IF(cout<< \" Clock loop \" <<endl;); \n " ) ;
# endif
2006-08-30 23:07:55 +02:00
puts ( " vlSymsp->__Vm_activity = true; \n " ) ;
puts ( " _eval(vlSymsp); \n " ) ;
2006-08-26 13:35:28 +02:00
# ifndef NEW_ORDERING
2006-08-30 23:07:55 +02:00
puts ( " __Vchange = _change_request(vlSymsp); \n " ) ;
2006-08-26 13:35:28 +02:00
puts ( " if (++__VclockLoop > 100) vl_fatal(__FILE__,__LINE__,__FILE__, \" Verilated model didn't converge \" ); \n " ) ;
puts ( " } \n " ) ;
# endif
puts ( " } \n " ) ;
//
2006-08-30 23:07:55 +02:00
puts ( " \n void " + modClassName ( modp ) + " ::_eval_initial_loop( " + EmitCBaseVisitor : : symClassVar ( ) + " ) { \n " ) ;
puts ( " vlSymsp->__Vm_didInit = true; \n " ) ;
puts ( " _eval_initial(vlSymsp); \n " ) ;
2006-08-26 13:35:28 +02:00
# ifndef NEW_ORDERING
2006-08-30 23:07:55 +02:00
puts ( " vlSymsp->__Vm_activity = true; \n " ) ;
2006-08-26 13:35:28 +02:00
puts ( " int __VclockLoop = 0; \n " ) ;
2006-08-30 23:07:55 +02:00
puts ( " IData __Vchange=1; \n " ) ;
puts ( " while (VL_LIKELY(__Vchange)) { \n " ) ;
2006-08-26 13:35:28 +02:00
# endif
2006-08-30 23:07:55 +02:00
puts ( " _eval_settle(vlSymsp); \n " ) ;
puts ( " _eval(vlSymsp); \n " ) ;
2006-08-26 13:35:28 +02:00
# ifndef NEW_ORDERING
2006-08-30 23:07:55 +02:00
puts ( " __Vchange = _change_request(vlSymsp); \n " ) ;
2006-08-26 13:35:28 +02:00
puts ( " if (++__VclockLoop > 100) vl_fatal(__FILE__,__LINE__,__FILE__, \" Verilated model didn't DC converge \" ); \n " ) ;
puts ( " } \n " ) ;
# endif
puts ( " } \n " ) ;
}
//----------------------------------------------------------------------
// Top interface/ implementation
void EmitCStmts : : emitVarList ( AstNode * firstp , EisWhich which , const string & prefixIfImp ) {
// Put out a list of signal declarations
2006-09-19 17:27:15 +02:00
// in order of 0:clocks, 1:vluint8, 2:vluint16, 4:vluint32, 5:vluint64, 6:wide, 7:arrays
2006-08-26 13:35:28 +02:00
// This aids cache packing and locality
2006-08-29 02:58:48 +02:00
// Largest->smallest reduces the number of pad variables.
// But for now, Smallest->largest makes it more likely a small offset will allow access to the signal.
for ( int isstatic = 1 ; isstatic > = 0 ; isstatic - - ) {
if ( prefixIfImp ! = " " & & ! isstatic ) continue ;
for ( int size = 0 ; size < 8 ; size + + ) {
if ( size = = 3 ) continue ;
for ( AstNode * nodep = firstp ; nodep ; nodep = nodep - > nextp ( ) ) {
if ( AstVar * varp = nodep - > castVar ( ) ) {
bool doit = true ;
switch ( which ) {
case EVL_ALL : doit = true ; break ;
case EVL_IO : doit = varp - > isIO ( ) ; break ;
case EVL_SIG : doit = ( varp - > isSignal ( ) & & ! varp - > isIO ( ) ) ; break ;
case EVL_TEMP : doit = varp - > isTemp ( ) ; break ;
default : v3fatalSrc ( " Bad Case " ) ;
}
if ( varp - > isStatic ( ) ? ! isstatic : isstatic ) doit = false ;
if ( doit ) {
int sigbytes = varp - > widthAlignBytes ( ) ;
if ( varp - > isUsedClock ( ) & & varp - > widthMin ( ) = = 1 ) sigbytes = 0 ;
else if ( varp - > arraysp ( ) ) sigbytes = 7 ;
else if ( varp - > isScWide ( ) ) sigbytes = 6 ;
else if ( sigbytes = = 8 ) sigbytes = 5 ;
else if ( sigbytes = = 4 ) sigbytes = 4 ;
else if ( sigbytes = = 2 ) sigbytes = 2 ;
else if ( sigbytes = = 1 ) sigbytes = 1 ;
if ( size = = sigbytes ) {
emitVarDecl ( varp , prefixIfImp ) ;
}
2006-08-26 13:35:28 +02:00
}
}
}
}
2006-08-29 02:58:48 +02:00
ofp ( ) - > putAlign ( isstatic , 4 , 0 , prefixIfImp . c_str ( ) ) ;
2006-08-26 13:35:28 +02:00
}
}
struct CmpName {
inline bool operator ( ) ( const AstNode * lhsp , const AstNode * rhsp ) const {
return lhsp - > name ( ) < rhsp - > name ( ) ;
}
} ;
void EmitCImp : : emitIntFuncDecls ( AstModule * modp ) {
vector < AstCFunc * > funcsp ;
for ( AstNode * nodep = modp - > stmtsp ( ) ; nodep ; nodep = nodep - > nextp ( ) ) {
if ( AstCFunc * funcp = nodep - > castCFunc ( ) ) {
if ( ! funcp - > skipDecl ( ) ) {
funcsp . push_back ( funcp ) ;
}
}
}
sort ( funcsp . begin ( ) , funcsp . end ( ) , CmpName ( ) ) ;
for ( vector < AstCFunc * > : : iterator it = funcsp . begin ( ) ; it ! = funcsp . end ( ) ; + + it ) {
AstCFunc * funcp = * it ;
ofp ( ) - > putsPrivate ( funcp - > declPrivate ( ) ) ;
2006-08-29 14:01:02 +02:00
if ( funcp - > isStatic ( ) ) puts ( " static " ) ;
2006-08-26 13:35:28 +02:00
puts ( funcp - > rtnTypeVoid ( ) ) ; puts ( " \t " ) ;
puts ( funcp - > name ( ) ) ; puts ( " ( " + cFuncArgs ( funcp ) + " ); \n " ) ;
}
}
void EmitCImp : : emitInt ( AstModule * modp ) {
// Always have this first; gcc has short circuiting if #ifdef is first in a file
if ( ! optSystemPerl ( ) ) { // else done for us automatically
puts ( " #ifndef _ " + modClassName ( modp ) + " _H_ \n " ) ;
puts ( " #define _ " + modClassName ( modp ) + " _H_ \n " ) ;
puts ( " \n " ) ;
}
ofp ( ) - > putsIntTopInclude ( ) ;
puts ( " #include \" verilated.h \" \n " ) ;
if ( v3Global . opt . coverage ( ) ) {
puts ( " #include \" SpCoverage.h \" \n " ) ;
}
// Declare foreign instances up front to make C++ happy
puts ( " class " + symClassName ( ) + " ; \n " ) ;
for ( AstNode * nodep = modp - > stmtsp ( ) ; nodep ; nodep = nodep - > nextp ( ) ) {
if ( AstCell * cellp = nodep - > castCell ( ) ) {
puts ( " class " + modClassName ( cellp - > modp ( ) ) + " ; \n " ) ;
}
}
puts ( " \n //---------- \n \n " ) ;
emitTextSection ( AstType : : SCHDR ) ;
if ( optSystemC ( ) & & modp - > isTop ( ) ) {
puts ( " SC_MODULE( " + modClassName ( modp ) + " ) { \n " ) ;
} else {
puts ( " VL_MODULE( " + modClassName ( modp ) + " ) { \n " ) ;
}
if ( optSystemPerl ( ) ) puts ( " /*AUTOATTR(verilated)*/ \n \n " ) ;
ofp ( ) - > resetPrivate ( ) ;
ofp ( ) - > putsPrivate ( false ) ; // public:
// Instantiated modules
if ( optSystemPerl ( ) ) {
puts ( " /*AUTOSUBCELLS*/ \n \n " ) ;
} else {
puts ( " // CELLS \n " ) ;
for ( AstNode * nodep = modp - > stmtsp ( ) ; nodep ; nodep = nodep - > nextp ( ) ) {
if ( AstCell * cellp = nodep - > castCell ( ) ) {
ofp ( ) - > putsCellDecl ( modClassName ( cellp - > modp ( ) ) , cellp - > name ( ) ) ;
}
}
}
puts ( " \n // PORTS \n " ) ;
emitVarList ( modp - > stmtsp ( ) , EVL_IO , " " ) ;
puts ( " \n // LOCAL SIGNALS \n " ) ;
emitVarList ( modp - > stmtsp ( ) , EVL_SIG , " " ) ;
puts ( " \n // LOCAL VARIABLES \n " ) ;
emitVarList ( modp - > stmtsp ( ) , EVL_TEMP , " " ) ;
puts ( " \n // INTERNAL VARIABLES \n " ) ;
ofp ( ) - > putsPrivate ( ! modp - > isTop ( ) ) ; // private: unless top
2006-08-29 02:58:48 +02:00
ofp ( ) - > putAlign ( V3OutFile : : AL_AUTO , 8 ) ;
2006-08-26 13:35:28 +02:00
puts ( symClassName ( ) + " * \t __VlSymsp; \t \t // Symbol table \n " ) ;
ofp ( ) - > putsPrivate ( false ) ; // public:
if ( modp - > isTop ( ) ) {
2006-08-29 02:27:04 +02:00
if ( v3Global . opt . inhibitSim ( ) ) {
2006-08-29 02:58:48 +02:00
ofp ( ) - > putAlign ( V3OutFile : : AL_AUTO , sizeof ( bool ) ) ;
2006-08-29 02:27:04 +02:00
puts ( " bool \t __Vm_inhibitSim; \t ///< Set true to disable evaluation of module \n " ) ;
}
2006-08-26 13:35:28 +02:00
}
2006-08-29 02:58:48 +02:00
ofp ( ) - > putAlign ( V3OutFile : : AL_AUTO , 8 ) ;
2006-08-26 13:35:28 +02:00
emitCoverageDecl ( modp ) ; // may flip public/private
2006-08-29 02:58:48 +02:00
ofp ( ) - > putAlign ( V3OutFile : : AL_AUTO , 8 ) ;
2006-08-26 13:35:28 +02:00
puts ( " \n // PARAMETERS \n " ) ;
ofp ( ) - > putsPrivate ( false ) ; // public:
for ( AstNode * nodep = modp - > stmtsp ( ) ; nodep ; nodep = nodep - > nextp ( ) ) {
if ( AstVar * varp = nodep - > castVar ( ) ) {
if ( varp - > isParam ( ) & & ( varp - > isUsedParam ( ) | | varp - > isSigPublic ( ) ) ) {
if ( ! varp - > initp ( ) ) nodep - > v3fatalSrc ( " No init for a param? " ) ;
// These should be static const values, however microsloth VC++ doesn't
// support them. They also cause problems with GDB under GCC2.95.
if ( varp - > isScWide ( ) ) { // Unsupported for output
puts ( " // enum WData " + varp - > name ( ) + " //wide " ) ;
} else if ( ! varp - > initp ( ) - > castConst ( ) ) { // Unsupported for output
puts ( " // enum IData " + varp - > name ( ) + " //not simple value " ) ;
} else {
puts ( " enum " ) ;
puts ( varp - > isQuad ( ) ? " _QData " : " _IData " ) ;
puts ( " " + varp - > name ( ) + " { " + varp - > name ( ) + " = " ) ;
varp - > initp ( ) - > iterateAndNext ( * this ) ;
puts ( " }; " ) ;
}
puts ( " \n " ) ;
}
}
}
puts ( " \n // METHODS \n " ) ;
ofp ( ) - > resetPrivate ( ) ;
2006-08-30 23:07:55 +02:00
// We don't need a private copy constructor, as VerilatedModule has one for us.
ofp ( ) - > putsPrivate ( true ) ;
puts ( modClassName ( modp ) + " & operator= (const " + modClassName ( modp ) + " &); \t ///< Copying not allowed \n " ) ;
puts ( modClassName ( modp ) + " (const " + modClassName ( modp ) + " &); \t ///< Copying not allowed \n " ) ;
2006-08-26 13:35:28 +02:00
ofp ( ) - > putsPrivate ( false ) ; // public:
if ( optSystemC ( ) & & modp - > isTop ( ) ) {
puts ( " SC_CTOR( " + modClassName ( modp ) + " ); \n " ) ;
2006-08-30 19:27:53 +02:00
puts ( " virtual ~ " + modClassName ( modp ) + " (); \n " ) ;
2006-08-26 13:35:28 +02:00
} else if ( optSystemC ( ) ) {
puts ( " VL_CTOR( " + modClassName ( modp ) + " ); \n " ) ;
2006-08-30 19:27:53 +02:00
puts ( " ~ " + modClassName ( modp ) + " (); \n " ) ;
2006-08-26 13:35:28 +02:00
} else {
puts ( modClassName ( modp ) + " (const char* name= \" TOP \" ); \n " ) ;
2006-08-30 19:27:53 +02:00
puts ( " ~ " + modClassName ( modp ) + " (); \n " ) ;
2006-08-26 13:35:28 +02:00
if ( v3Global . opt . trace ( ) ) {
puts ( " void \t trace (SpTraceVcdCFile* tfp, int levels, int options=0); \n " ) ;
}
}
2006-08-30 03:14:29 +02:00
puts ( " void \t __Vconfigure( " + symClassName ( ) + " * symsp); \n " ) ;
2006-08-26 13:35:28 +02:00
if ( optSystemPerl ( ) ) puts ( " /*AUTOMETHODS*/ \n " ) ;
emitTextSection ( AstType : : SCINT ) ;
puts ( " \n // Sensitivity blocks \n " ) ;
if ( modp - > isTop ( ) ) {
puts ( " void \t final(); \t ///< Function to call when simulation completed \n " ) ;
if ( optSystemC ( ) ) ofp ( ) - > putsPrivate ( true ) ; ///< eval() is invoked by our sensitive() calls.
puts ( " void \t eval(); \t ///< Main function to call from calling app when inputs change \n " ) ;
2006-08-29 02:27:04 +02:00
if ( v3Global . opt . inhibitSim ( ) ) {
puts ( " void \t inhibitSim(bool flag) { __Vm_inhibitSim=flag; } \t ///< Set true to disable evaluation of module \n " ) ;
}
2006-08-26 13:35:28 +02:00
ofp ( ) - > putsPrivate ( true ) ; // private:
2006-08-31 00:00:55 +02:00
puts ( " static void _eval_initial_loop( " + EmitCBaseVisitor : : symClassVar ( ) + " ); \n " ) ;
2006-08-26 13:35:28 +02:00
}
emitIntFuncDecls ( modp ) ;
if ( ! optSystemPerl ( ) & & v3Global . opt . trace ( ) ) {
ofp ( ) - > putsPrivate ( false ) ; // public:
2006-08-31 00:00:55 +02:00
puts ( " static void traceInit (SpTraceVcd* vcdp, void* userthis, uint32_t code); \n " ) ;
puts ( " static void traceFull (SpTraceVcd* vcdp, void* userthis, uint32_t code); \n " ) ;
puts ( " static void traceChg (SpTraceVcd* vcdp, void* userthis, uint32_t code); \n " ) ;
2006-08-26 13:35:28 +02:00
}
2006-08-31 00:00:55 +02:00
puts ( " } VL_ATTR_ALIGNED(64); \n " ) ;
2006-08-26 13:35:28 +02:00
puts ( " \n " ) ;
// finish up h-file
if ( ! optSystemPerl ( ) ) {
puts ( " #endif /*guard*/ \n " ) ;
}
}
//----------------------------------------------------------------------
void EmitCImp : : emitImp ( AstModule * modp ) {
if ( optSystemPerl ( ) ) {
puts ( " //############################################################ \n " ) ;
puts ( " #sp implementation \n " ) ;
}
ofp ( ) - > printf ( " #include \" %-20s // For This \n " ,
( modClassName ( modp ) + " .h \" " ) . c_str ( ) ) ;
// Us
2006-08-30 23:07:55 +02:00
puts ( " #include \" " + symClassName ( ) + " .h \" \n " ) ;
2006-08-26 13:35:28 +02:00
if ( optSystemPerl ( ) & & ( m_splitFilenum | | ! m_fast ) ) {
puts ( " \n " ) ;
puts ( " SP_MODULE_CONTINUED( " + modClassName ( modp ) + " ); \n " ) ;
}
emitTextSection ( AstType : : SCIMPHDR ) ;
2006-08-29 02:58:48 +02:00
if ( m_slow & & m_splitFilenum = = 0 ) {
puts ( " \n //-------------------- \n " ) ;
puts ( " // STATIC VARIABLES \n \n " ) ;
emitVarList ( modp - > stmtsp ( ) , EVL_ALL , modClassName ( modp ) ) ;
}
2006-08-26 13:35:28 +02:00
if ( m_fast & & m_splitFilenum = = 0 ) {
emitTextSection ( AstType : : SCIMP ) ;
emitStaticDecl ( modp ) ;
}
if ( m_slow & & m_splitFilenum = = 0 ) {
puts ( " \n //-------------------- \n " ) ;
2006-08-30 19:27:53 +02:00
emitCtorImp ( modp ) ;
emitConfigureImp ( modp ) ;
emitDestructorImp ( modp ) ;
2006-08-30 03:14:29 +02:00
emitCoverageImp ( modp ) ;
2006-08-26 13:35:28 +02:00
}
2006-08-30 19:27:53 +02:00
2006-08-26 13:35:28 +02:00
if ( m_fast & & m_splitFilenum = = 0 ) {
if ( modp - > isTop ( ) ) {
emitStaticDecl ( modp ) ;
puts ( " \n //-------------------- \n " ) ;
puts ( " \n " ) ;
emitWrapEval ( modp ) ;
}
}
if ( m_fast & & m_splitFilenum = = 0 ) {
if ( v3Global . opt . trace ( ) & & optSystemC ( ) & & m_modp - > isTop ( ) ) {
puts ( " \n " ) ;
puts ( " \n /*AUTOTRACE(__MODULE__,recurse,activity,exists)*/ \n \n " ) ;
}
}
// Blocks
puts ( " \n //-------------------- \n " ) ;
puts ( " // Internal Methods \n " ) ;
}
void EmitCImp : : emitImpBottom ( AstModule * modp ) {
}
//######################################################################
void EmitCImp : : main ( AstModule * modp , bool slow , bool fast ) {
// Output a module
m_modp = modp ;
m_slow = slow ;
m_fast = fast ;
string filenameNoExt = v3Global . opt . makeDir ( ) + " / " + modClassName ( modp ) + ( m_fast ? " " : " __Slow " ) ;
if ( debug ( ) > = 5 ) {
for ( int i = 0 ; i < modp - > level ( ) ; i + + ) { cout < < " " ; }
UINFONL ( 0 , " Emitting " < < modClassName ( modp ) < < endl ) ;
}
if ( optSystemPerl ( ) ) {
m_ofp = newOutCFile ( modp , ! m_fast , true ) ;
if ( m_fast ) {
puts ( " #sp interface \n " ) ;
emitInt ( modp ) ;
}
}
else if ( optSystemC ( ) ) {
if ( m_fast ) {
m_ofp = newOutCFile ( modp , ! m_fast , false /*source*/ ) ;
emitInt ( modp ) ;
delete m_ofp ; m_ofp = NULL ;
}
m_ofp = newOutCFile ( modp , ! m_fast , true /*source*/ ) ;
}
else {
if ( m_fast ) {
m_ofp = newOutCFile ( modp , ! m_fast , false /*source*/ ) ;
emitInt ( modp ) ;
delete m_ofp ; m_ofp = NULL ;
}
m_ofp = newOutCFile ( modp , ! m_fast , true /*source*/ ) ;
}
emitImp ( modp ) ;
for ( AstNode * nodep = modp - > stmtsp ( ) ; nodep ; nodep = nodep - > nextp ( ) ) {
if ( AstCFunc * funcp = nodep - > castCFunc ( ) ) {
if ( v3Global . opt . outputSplit ( ) > 1 & & splitSize ( )
& & v3Global . opt . outputSplit ( ) < splitSize ( ) ) {
// Close old file
emitImpBottom ( modp ) ;
delete m_ofp ; m_ofp = NULL ;
// Open a new file
m_splitSize = 0 ;
m_ofp = newOutCFile ( modp , ! m_fast , true /*source*/ , + + m_splitFilenum ) ;
emitImp ( modp ) ;
}
mainDoFunc ( funcp ) ;
}
}
emitImpBottom ( modp ) ;
delete m_ofp ; m_ofp = NULL ;
}
//######################################################################
// Tracing routines
class EmitCTrace : EmitCStmts {
AstCFunc * m_funcp ; // Function we're in now
bool m_slow ; // Making slow file
// METHODS
void emitTraceHeader ( ) {
// Includes
if ( optSystemC ( ) ) {
puts ( " #include \" SpTraceVcd.h \" \n " ) ;
}
puts ( " #include \" SpTraceVcdC.h \" \n " ) ;
puts ( " #include \" " + symClassName ( ) + " .h \" \n " ) ;
puts ( " \n " ) ;
}
void emitTraceSlow ( ) {
puts ( " \n //====================== \n \n " ) ;
puts ( " void " + topClassName ( ) + " ::trace ( " ) ;
if ( optSystemC ( ) ) {
puts ( " SpTraceFile* tfp, int, int) { \n " ) ;
} else {
puts ( " SpTraceVcdCFile* tfp, int, int) { \n " ) ;
}
puts ( " tfp->spTrace()->addCallback ( "
" & " + topClassName ( ) + " ::traceInit "
+ " , & " + topClassName ( ) + " ::traceFull "
+ " , & " + topClassName ( ) + " ::traceChg, this); \n " ) ;
puts ( " } \n " ) ;
puts ( " void " + topClassName ( ) + " ::traceInit(SpTraceVcd* vcdp, void* userthis, uint32_t code) { \n " ) ;
puts ( " // Callback from vcd->open() \n " ) ;
puts ( topClassName ( ) + " * t=( " + topClassName ( ) + " *)userthis; \n " ) ;
2006-08-30 23:07:55 +02:00
puts ( EmitCBaseVisitor : : symClassVar ( ) + " = t->__VlSymsp; // Setup global symbol table \n " ) ;
2006-08-26 13:35:28 +02:00
puts ( " if (!Verilated::calcUnusedSigs()) vl_fatal(__FILE__,__LINE__,__FILE__, \" Turning on wave traces requires Verilated::traceEverOn(true) call before time 0. \" ); \n " ) ;
2006-08-30 23:07:55 +02:00
puts ( " t->traceInitThis (vlSymsp, vcdp, code); \n " ) ;
2006-08-26 13:35:28 +02:00
puts ( " } \n " ) ;
puts ( " void " + topClassName ( ) + " ::traceFull(SpTraceVcd* vcdp, void* userthis, uint32_t code) { \n " ) ;
puts ( " // Callback from vcd->dump() \n " ) ;
puts ( topClassName ( ) + " * t=( " + topClassName ( ) + " *)userthis; \n " ) ;
2006-08-30 23:07:55 +02:00
puts ( EmitCBaseVisitor : : symClassVar ( ) + " = t->__VlSymsp; // Setup global symbol table \n " ) ;
puts ( " t->traceFullThis (vlSymsp, vcdp, code); \n " ) ;
2006-08-26 13:35:28 +02:00
puts ( " } \n " ) ;
puts ( " \n //====================== \n \n " ) ;
}
void emitTraceFast ( ) {
puts ( " \n //====================== \n \n " ) ;
puts ( " void " + topClassName ( ) + " ::traceChg(SpTraceVcd* vcdp, void* userthis, uint32_t code) { \n " ) ;
puts ( " // Callback from vcd->dump() \n " ) ;
puts ( topClassName ( ) + " * t=( " + topClassName ( ) + " *)userthis; \n " ) ;
2006-08-30 23:07:55 +02:00
puts ( EmitCBaseVisitor : : symClassVar ( ) + " = t->__VlSymsp; // Setup global symbol table \n " ) ;
puts ( " if (vlSymsp->getClearActivity()) { \n " ) ;
puts ( " t->traceChgThis (vlSymsp, vcdp, code); \n " ) ;
2006-08-26 13:35:28 +02:00
puts ( " } \n " ) ;
puts ( " } \n " ) ;
puts ( " \n //====================== \n \n " ) ;
}
bool emitTraceIsScWide ( AstTraceInc * nodep ) {
AstVarRef * varrefp = nodep - > valuep ( ) - > castVarRef ( ) ;
if ( ! varrefp ) return false ;
AstVar * varp = varrefp - > varp ( ) ;
return varp - > isSc ( ) & & varp - > isScWide ( ) ;
}
void emitTraceInitOne ( AstTraceDecl * nodep ) {
if ( nodep - > isWide ( ) ) {
puts ( " vcdp->declArray " ) ;
} else if ( nodep - > isQuad ( ) ) {
puts ( " vcdp->declQuad " ) ;
} else if ( nodep - > msb ( ) | | nodep - > lsb ( ) ) {
puts ( " vcdp->declBus " ) ;
} else {
puts ( " vcdp->declBit " ) ;
}
puts ( " (c+ " + cvtToStr ( nodep - > code ( ) ) ) ;
if ( nodep - > arrayWidth ( ) ) puts ( " +i* " + cvtToStr ( nodep - > widthWords ( ) ) ) ;
puts ( " , \" " + nodep - > showname ( ) + " \" " ) ;
if ( nodep - > arrayWidth ( ) ) {
puts ( " ,(i+ " + cvtToStr ( nodep - > arrayLsb ( ) ) + " ) " ) ;
} else {
puts ( " ,-1 " ) ;
}
if ( nodep - > msb ( ) | | nodep - > lsb ( ) ) {
puts ( " , " + cvtToStr ( nodep - > msb ( ) ) + " , " + cvtToStr ( nodep - > lsb ( ) ) ) ;
}
puts ( " ); " ) ;
}
void emitTraceChangeOne ( AstTraceInc * nodep , int arrayindex ) {
nodep - > precondsp ( ) - > iterateAndNext ( * this ) ;
string full = ( m_funcp - > funcType ( ) = = AstCFuncType : : TRACE_FULL ) ? " full " : " chg " ;
if ( nodep - > isWide ( ) | | emitTraceIsScWide ( nodep ) ) {
puts ( " vcdp-> " + full + " Array " ) ;
} else if ( nodep - > isQuad ( ) ) {
puts ( " vcdp-> " + full + " Quad " ) ;
} else if ( nodep - > declp ( ) - > msb ( ) | | nodep - > declp ( ) - > lsb ( ) ) {
puts ( " vcdp-> " + full + " Bus " ) ;
} else {
puts ( " vcdp-> " + full + " Bit " ) ;
}
puts ( " (c+ " + cvtToStr ( nodep - > declp ( ) - > code ( )
+ ( ( arrayindex < 0 ) ? 0 : ( arrayindex * nodep - > declp ( ) - > widthWords ( ) ) ) ) ) ;
puts ( " , " ) ;
emitTraceValue ( nodep , arrayindex ) ;
if ( nodep - > declp ( ) - > msb ( ) | | nodep - > declp ( ) - > lsb ( ) ) {
puts ( " , " + cvtToStr ( nodep - > declp ( ) - > widthMin ( ) ) ) ;
}
puts ( " ); \n " ) ;
}
void emitTraceValue ( AstTraceInc * nodep , int arrayindex ) {
if ( nodep - > valuep ( ) - > castVarRef ( ) ) {
AstVarRef * varrefp = nodep - > valuep ( ) - > castVarRef ( ) ;
AstVar * varp = varrefp - > varp ( ) ;
if ( emitTraceIsScWide ( nodep ) ) puts ( " (uint32_t*) " ) ;
puts ( " ( " ) ;
varrefp - > iterate ( * this ) ; // Put var name out
if ( varp - > arraysp ( ) ) {
if ( arrayindex = = - 2 ) puts ( " [i] " ) ;
else if ( arrayindex = = - 1 ) puts ( " [0] " ) ;
else puts ( " [ " + cvtToStr ( arrayindex ) + " ] " ) ;
}
if ( varp - > isSc ( ) ) puts ( " .read() " ) ;
if ( emitTraceIsScWide ( nodep ) ) puts ( " .get_datap() " ) ;
puts ( " ) " ) ;
} else {
puts ( " ( " ) ;
nodep - > valuep ( ) - > iterate ( * this ) ;
puts ( " ) " ) ;
}
}
// VISITORS
virtual void visit ( AstNetlist * nodep , AstNUser * ) {
// Top module only
nodep - > topModulep ( ) - > accept ( * this ) ;
}
virtual void visit ( AstModule * nodep , AstNUser * ) {
nodep - > iterateChildren ( * this ) ;
}
virtual void visit ( AstCFunc * nodep , AstNUser * ) {
if ( nodep - > slow ( ) ! = m_slow ) return ;
if ( nodep - > funcType ( ) = = AstCFuncType : : TRACE_INIT
| | nodep - > funcType ( ) = = AstCFuncType : : TRACE_FULL
| | nodep - > funcType ( ) = = AstCFuncType : : TRACE_CHANGE ) {
m_funcp = nodep ;
puts ( " \n " ) ;
puts ( nodep - > rtnTypeVoid ( ) ) ; puts ( " " ) ;
puts ( topClassName ( ) + " :: " + nodep - > name ( )
+ " ( " + cFuncArgs ( nodep ) + " ) { \n " ) ;
2006-08-31 00:00:55 +02:00
if ( nodep - > symProlog ( ) ) puts ( EmitCBaseVisitor : : symTopAssign ( ) + " \n " ) ;
2006-08-26 13:35:28 +02:00
puts ( " int c=code; \n " ) ;
puts ( " if (0 && vcdp && c) {} // Prevent unused \n " ) ;
if ( nodep - > funcType ( ) = = AstCFuncType : : TRACE_INIT ) {
2006-08-31 00:00:55 +02:00
puts ( " vcdp->module(vlSymsp->name()); // Setup signal names \n " ) ;
2006-08-26 13:35:28 +02:00
} else if ( nodep - > funcType ( ) = = AstCFuncType : : TRACE_FULL ) {
} else if ( nodep - > funcType ( ) = = AstCFuncType : : TRACE_CHANGE ) {
} else nodep - > v3fatalSrc ( " Bad Case " ) ;
if ( nodep - > initsp ( ) ) puts ( " // Variables \n " ) ;
emitVarList ( nodep - > initsp ( ) , EVL_ALL , " " ) ;
nodep - > initsp ( ) - > iterateAndNext ( * this ) ;
2006-08-29 02:58:48 +02:00
ofp ( ) - > putAlign ( V3OutFile : : AL_AUTO , 4 ) ;
2006-08-26 13:35:28 +02:00
puts ( " // Body \n " ) ;
puts ( " { \n " ) ;
// Do the statements Note not from this node, but the TRACE_INIT's.
// That saved us from having 3 copies of all of the TRACEs
nodep - > stmtsp ( ) - > iterateAndNext ( * this ) ;
puts ( " } \n " ) ;
if ( nodep - > finalsp ( ) ) puts ( " // Final \n " ) ;
nodep - > finalsp ( ) - > iterateAndNext ( * this ) ;
puts ( " } \n " ) ;
}
m_funcp = NULL ;
}
virtual void visit ( AstTraceDecl * nodep , AstNUser * ) {
if ( nodep - > arrayWidth ( ) ) {
puts ( " {int i; for (i=0; i< " + cvtToStr ( nodep - > arrayWidth ( ) ) + " ; i++) { \n " ) ;
emitTraceInitOne ( nodep ) ;
puts ( " }} \n " ) ;
} else {
emitTraceInitOne ( nodep ) ;
puts ( " \n " ) ;
}
}
virtual void visit ( AstTraceInc * nodep , AstNUser * ) {
if ( nodep - > declp ( ) - > arrayWidth ( ) ) {
// It traces faster if we unroll the loop
for ( unsigned i = 0 ; i < nodep - > declp ( ) - > arrayWidth ( ) ; i + + ) {
emitTraceChangeOne ( nodep , i ) ;
}
} else {
emitTraceChangeOne ( nodep , - 1 ) ;
}
}
virtual void visit ( AstCoverDecl * nodep , AstNUser * ) {
}
virtual void visit ( AstCoverInc * nodep , AstNUser * ) {
}
public :
EmitCTrace ( bool slow ) {
m_funcp = NULL ;
m_slow = slow ;
}
virtual ~ EmitCTrace ( ) { }
void main ( ) {
// Put out the file
string filename = ( v3Global . opt . makeDir ( ) + " / " + topClassName ( )
+ ( m_slow ? " __Trace__Slow.cpp " : " __Trace.cpp " ) ) ;
AstCFile * cfilep = newCFile ( filename , m_slow , true /*source*/ ) ;
cfilep - > support ( true ) ;
V3OutCFile of ( filename ) ;
of . putsHeader ( ) ;
m_ofp = & of ;
emitTraceHeader ( ) ;
if ( m_slow ) emitTraceSlow ( ) ;
else emitTraceFast ( ) ;
v3Global . rootp ( ) - > accept ( * this ) ;
m_ofp = NULL ;
}
} ;
//######################################################################
// EmitC class functions
void V3EmitC : : emitc ( ) {
UINFO ( 2 , __FUNCTION__ < < " : " < < endl ) ;
// Process each module in turn
for ( AstModule * nodep = v3Global . rootp ( ) - > modulesp ( ) ; nodep ; nodep = nodep - > nextp ( ) - > castModule ( ) ) {
if ( v3Global . opt . outputSplit ( ) ) {
{ EmitCImp imp ; imp . main ( nodep , false , true ) ; }
{ EmitCImp imp ; imp . main ( nodep , true , false ) ; }
} else {
{ EmitCImp imp ; imp . main ( nodep , true , true ) ; }
}
}
}
void V3EmitC : : emitcTrace ( ) {
UINFO ( 2 , __FUNCTION__ < < " : " < < endl ) ;
if ( v3Global . opt . trace ( ) ) {
{ EmitCTrace trace ( true ) ; trace . main ( ) ; }
{ EmitCTrace trace ( false ) ; trace . main ( ) ; }
}
}