2006-08-26 11:35:28 +00:00
//*************************************************************************
// DESCRIPTION: Verilator: Emit C++ for tree
//
2008-04-25 12:14:27 +00:00
// Code available from: http://www.veripool.org/verilator
2006-08-26 11:35:28 +00:00
//
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
//
//*************************************************************************
//
2009-01-02 11:47:39 -05:00
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
2006-08-26 11:35:28 +00:00
// redistribute it and/or modify it under the terms of either the GNU
2009-05-04 17:07:57 -04:00
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
2006-08-26 11:35:28 +00:00
//
// 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.
//
//*************************************************************************
2006-12-18 19:20:45 +00:00
#include "config_build.h"
#include "verilatedos.h"
2008-06-30 13:11:25 -04:00
#include <cstdio>
#include <cstdarg>
2006-08-26 11:35:28 +00:00
#include <unistd.h>
2008-06-30 13:11:25 -04:00
#include <cmath>
2006-08-26 11:35:28 +00:00
#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
//######################################################################
// 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
2008-11-17 17:13:57 -05:00
int m_splitSize ; // # of cfunc nodes placed into output file
int m_splitFilenum ; // File number being created, 0 = primary
2009-01-21 16:56:50 -05:00
2006-08-26 11:35:28 +00:00
public :
2009-01-21 16:56:50 -05:00
// METHODS
static int debug () {
static int level = - 1 ;
if ( VL_UNLIKELY ( level < 0 )) level = v3Global . opt . debugSrcLevel ( __FILE__ );
return level ;
}
2006-08-26 11:35:28 +00:00
2008-11-17 17:13:57 -05:00
// ACCESSORS
int splitFilenum () { return m_splitFilenum ; }
int splitFilenumInc () { m_splitSize = 0 ; return ++ m_splitFilenum ; }
int splitSize () { return m_splitSize ; }
void splitSizeInc ( AstNode * nodep ) { m_splitSize += EmitCBaseCounterVisitor ( nodep ). count (); }
bool splitNeeded () { return ( splitSize () && v3Global . opt . outputSplit () > 1
&& v3Global . opt . outputSplit () < splitSize ()); }
2006-08-26 11:35:28 +00:00
// METHODS
2008-07-01 14:15:10 -04:00
void displayNode ( AstNode * nodep , const string & vformat , AstNode * exprsp , bool isScan );
void displayEmit ( AstNode * nodep , bool isScan );
void displayArg ( AstNode * dispp , AstNode ** elistp , bool isScan ,
string vfmt , char fmtLetter );
2006-08-26 11:35:28 +00:00
void emitVarDecl ( AstVar * nodep , const string & prefixIfImp );
2006-08-29 00:58:48 +00:00
typedef enum { EVL_IO , EVL_SIG , EVL_TEMP , EVL_STATIC , EVL_ALL } EisWhich ;
2006-08-26 11:35:28 +00: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" ));
}
2009-03-13 22:58:55 -04:00
void emitScIQW ( AstVar * nodep ) {
puts ( nodep -> isScBv () ? "SW" : ( nodep -> isScQuad () ? "SQ" : "SI" ));
}
2008-06-29 20:02:24 -04:00
void emitOpName ( AstNode * nodep , const string & format ,
AstNode * lhsp , AstNode * rhsp , AstNode * thsp );
2006-08-26 11:35:28 +00:00
string cFuncArgs ( AstCFunc * nodep ) {
// Return argument list for given C function
string args = nodep -> argTypes ();
2006-10-11 15:41:42 +00:00
// 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 += ", " ;
if ( portp -> isWide ()) {
if ( portp -> isInOnly ()) args += "const " ;
args += portp -> cType ();
args += " (& " + portp -> name ();
args += ")[" + cvtToStr ( portp -> widthWords ()) + "]" ;
} else {
args += portp -> cType ();
if ( portp -> isOutput ()) args += "&" ;
args += " " + portp -> name ();
2006-08-26 11:35:28 +00:00
}
}
}
}
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
2009-03-13 22:58:55 -04:00
emitScIQW ( nodep -> lhsp () -> castVarRef () -> varp ());
2006-08-26 11:35:28 +00:00
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 );
2009-03-13 22:58:55 -04:00
emitScIQW ( nodep -> rhsp () -> castVarRef () -> varp ());
puts ( "(" );
2006-08-26 11:35:28 +00:00
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 21:07:55 +00:00
puts ( nodep -> argTypes ());
bool comma = ( nodep -> argTypes () != "" );
2006-08-26 11:35:28 +00:00
for ( AstNode * subnodep = nodep -> argsp (); subnodep ; subnodep = subnodep -> nextp ()) {
2006-08-30 21:07:55 +00:00
if ( comma ) puts ( ", " );
2006-08-26 11:35:28 +00:00
subnodep -> accept ( * this );
2006-08-30 21:07:55 +00:00
comma = true ;
2006-08-26 11:35:28 +00: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 01:14:29 +00:00
puts ( "__vlCoverInsert(" ); // As Declared in emitCoverageDecl
2008-12-05 10:54:14 -05:00
puts ( "&(vlSymsp->__Vcoverage[" );
2008-12-12 15:34:02 -05:00
puts ( cvtToStr ( nodep -> dataDeclThisp () -> binNum ())); puts ( "])" );
2008-12-05 10:54:14 -05:00
// If this isn't the first instantiation of this module under this
// design, don't really count the bucket, and rely on SystemPerl to
// aggregate counts. This is because Verilator combines all
// hiearchies itself, and if SystemPerl also did it, you'd end up
// with (number-of-instant) times too many counts in this bin.
puts ( ", first" ); // Enable, passed from __Vconfigure parameter
2009-05-08 13:16:19 -04:00
puts ( ", " ); putsQuoted ( nodep -> fileline () -> filename ());
2006-08-26 11:35:28 +00:00
puts ( ", " ); puts ( cvtToStr ( nodep -> fileline () -> lineno ()));
puts ( ", " ); puts ( cvtToStr ( nodep -> column ()));
2009-05-08 13:16:19 -04:00
puts ( ", " ); putsQuoted (( nodep -> hier () != "" ? "." : "" ) + nodep -> hier ());
puts ( ", " ); putsQuoted ( nodep -> page ());
puts ( ", " ); putsQuoted ( nodep -> comment ());
2006-08-26 11:35:28 +00:00
puts ( "); \n " );
}
virtual void visit ( AstCoverInc * nodep , AstNUser * ) {
2008-12-05 10:54:14 -05:00
puts ( "++(vlSymsp->__Vcoverage[" );
2008-12-12 15:34:02 -05:00
puts ( cvtToStr ( nodep -> declp () -> dataDeclThisp () -> binNum ()));
2008-12-05 10:54:14 -05:00
puts ( "]); \n " );
2006-08-26 11:35:28 +00:00
}
virtual void visit ( AstCReturn * nodep , AstNUser * ) {
puts ( "return (" );
nodep -> lhsp () -> iterateAndNext ( * this );
puts ( "); \n " );
}
2008-07-01 14:15:10 -04:00
virtual void visit ( AstDisplay * nodep , AstNUser * ) {
string text = nodep -> text ();
if ( nodep -> addNewline ()) text += " \\ n" ;
displayNode ( nodep , text , nodep -> exprsp (), false );
}
virtual void visit ( AstFScanF * nodep , AstNUser * ) {
displayNode ( nodep , nodep -> text (), nodep -> exprsp (), true );
}
virtual void visit ( AstSScanF * nodep , AstNUser * ) {
displayNode ( nodep , nodep -> text (), nodep -> exprsp (), true );
}
2008-11-05 10:52:23 -05:00
virtual void visit ( AstFGetS * nodep , AstNUser * ) {
checkMaxWords ( nodep );
emitOpName ( nodep , nodep -> emitC (), nodep -> lhsp (), nodep -> rhsp (), NULL );
}
2008-07-01 14:15:10 -04:00
void checkMaxWords ( AstNode * nodep ) {
if ( nodep -> widthWords () > VL_TO_STRING_MAX_WORDS ) {
nodep -> v3error ( "String of " << nodep -> width () << " bits exceeds hardcoded limit VL_TO_STRING_MAX_WORDS in verilatedos.h \n " );
}
}
2006-08-26 11:35:28 +00:00
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 ( "(" );
2006-12-21 15:28:32 +00:00
if ( nodep -> filenamep () -> isWide ()) {
puts ( cvtToStr ( nodep -> filenamep () -> widthWords ()));
putbs ( ", " );
}
2008-07-01 14:15:10 -04:00
checkMaxWords ( nodep -> filenamep ());
2006-08-26 11:35:28 +00:00
nodep -> filenamep () -> iterateAndNext ( * this );
putbs ( ", " );
nodep -> modep () -> iterateAndNext ( * this );
puts ( "); \n " );
}
2006-12-19 14:09:57 +00:00
virtual void visit ( AstReadMem * nodep , AstNUser * ) {
puts ( "VL_READMEM_" );
emitIQW ( nodep -> filenamep ());
2007-11-30 22:12:53 +00:00
puts ( " (" ); // We take a void* rather than emitIQW(nodep->memp());
2006-12-19 14:09:57 +00:00
puts ( nodep -> isHex () ? "true" : "false" );
putbs ( "," );
puts ( cvtToStr ( nodep -> memp () -> widthMin ())); // Need real storage width
putbs ( "," );
uint32_t array_lsb = 0 ;
{
AstVarRef * varrefp = nodep -> memp () -> castVarRef ();
if ( ! varrefp || ! varrefp -> varp () -> arrayp ( 0 )) { nodep -> v3error ( "Readmem loading non-arrayed variable" ); }
else {
puts ( cvtToStr ( varrefp -> varp () -> arrayElements ()));
array_lsb = varrefp -> varp () -> arrayp ( 0 ) -> lsbConst ();
}
}
putbs ( ", " );
puts ( cvtToStr ( array_lsb ));
putbs ( "," );
puts ( cvtToStr ( nodep -> filenamep () -> widthWords ()));
2008-07-01 14:15:10 -04:00
checkMaxWords ( nodep -> filenamep ());
2006-12-19 14:09:57 +00:00
putbs ( ", " );
nodep -> filenamep () -> iterateAndNext ( * this );
putbs ( ", " );
nodep -> memp () -> iterateAndNext ( * this );
putbs ( "," ); if ( nodep -> lsbp ()) { nodep -> lsbp () -> iterateAndNext ( * this ); }
else puts ( cvtToStr ( array_lsb ));
putbs ( "," ); if ( nodep -> msbp ()) { nodep -> msbp () -> iterateAndNext ( * this ); } else puts ( "~0" );
puts ( "); \n " );
}
2006-08-26 11:35:28 +00:00
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 " );
}
2008-06-27 08:45:05 -04:00
virtual void visit ( AstFFlush * nodep , AstNUser * ) {
2008-07-16 14:06:08 -04:00
if ( ! nodep -> filep ()) {
puts ( "fflush (stdout); \n " );
} else {
puts ( "if (" );
nodep -> filep () -> iterateAndNext ( * this );
puts ( ") { fflush (VL_CVT_Q_FP(" );
nodep -> filep () -> iterateAndNext ( * this );
puts ( ")); } \n " );
}
2008-06-27 08:45:05 -04:00
}
2006-08-26 11:35:28 +00:00
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 * ) {
2009-05-08 13:16:19 -04:00
puts ( "vl_stop(" );
putsQuoted ( nodep -> fileline () -> filename ());
puts ( "," );
2006-08-26 11:35:28 +00:00
puts ( cvtToStr ( nodep -> fileline () -> lineno ()));
puts ( ", \"\" ); \n " );
}
virtual void visit ( AstFinish * nodep , AstNUser * ) {
2009-05-08 13:16:19 -04:00
puts ( "vl_finish(" );
putsQuoted ( nodep -> fileline () -> filename ());
puts ( "," );
2006-08-26 11:35:28 +00:00
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 * ) {
2008-06-29 20:02:24 -04:00
emitOpName ( nodep , nodep -> emitC (), NULL , NULL , NULL );
2006-08-26 11:35:28 +00:00
}
virtual void visit ( AstNodeUniop * nodep , AstNUser * ) {
if ( emitSimpleOk ( nodep )) {
putbs ( "(" ); puts ( nodep -> emitSimpleOperator ()); puts ( " " );
2008-06-29 20:02:24 -04:00
nodep -> lhsp () -> iterateAndNext ( * this ); puts ( ")" );
2006-08-26 11:35:28 +00:00
} else {
2008-06-29 20:02:24 -04:00
emitOpName ( nodep , nodep -> emitC (), nodep -> lhsp (), NULL , NULL );
2006-08-26 11:35:28 +00:00
}
}
virtual void visit ( AstNodeBiop * nodep , AstNUser * ) {
if ( emitSimpleOk ( nodep )) {
putbs ( "(" ); nodep -> lhsp () -> iterateAndNext ( * this );
puts ( " " ); putbs ( nodep -> emitSimpleOperator ()); puts ( " " );
2008-06-29 20:02:24 -04:00
nodep -> rhsp () -> iterateAndNext ( * this ); puts ( ")" );
2006-08-26 11:35:28 +00:00
} else {
2008-06-29 20:02:24 -04:00
emitOpName ( nodep , nodep -> emitC (), nodep -> lhsp (), nodep -> rhsp (), NULL );
2006-08-26 11:35:28 +00:00
}
}
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 ) {
2007-06-13 17:34:09 +00:00
nodep -> v3error ( "Unsupported: Signed multiply of " << nodep -> width () << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h \n " );
2006-08-26 11:35:28 +00:00
}
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 ()) {
2008-06-29 20:02:24 -04:00
emitOpName ( nodep , nodep -> emitC (), nodep -> condp (), nodep -> expr1p (), nodep -> expr2p ());
2006-08-26 11:35:28 +00:00
} 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
2008-06-29 20:02:24 -04:00
emitOpName ( nodep , nodep -> emitC (), nodep -> fromp (), nodep -> lsbp (), nodep -> thsp ());
2006-08-26 11:35:28 +00:00
}
virtual void visit ( AstReplicate * nodep , AstNUser * ) {
if ( nodep -> lhsp () -> widthMin () == 1 && ! nodep -> isWide ()) {
2008-09-04 11:03:46 -04:00
if ((( int ) nodep -> rhsp () -> castConst () -> toUInt ()
2006-08-26 11:35:28 +00:00
* 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 ( "," );
2008-06-29 20:02:24 -04:00
nodep -> lhsp () -> iterateAndNext ( * this ); puts ( ", " );
nodep -> rhsp () -> iterateAndNext ( * this ); puts ( ")" );
2006-08-26 11:35:28 +00:00
} else {
2008-06-29 20:02:24 -04:00
emitOpName ( nodep , nodep -> emitC (), nodep -> lhsp (), nodep -> rhsp (), NULL );
2006-08-26 11:35:28 +00:00
}
}
// Terminals
virtual void visit ( AstVarRef * nodep , AstNUser * ) {
puts ( nodep -> hiername ());
2008-06-12 12:03:47 -04:00
puts ( nodep -> varp () -> name ());
2006-08-26 11:35:28 +00:00
}
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 -- ) {
2009-04-08 21:47:48 -04:00
// Only 32 bits - llx + long long here just to appease CPP format warning
ofp () -> printf ( ",0x%08llx" , ( long long )( nodep -> num (). dataWord ( word )));
2006-08-26 11:35:28 +00:00
}
2009-04-08 21:47:48 -04:00
ofp () -> printf ( ",0x%08llx)" , ( long long )( nodep -> num (). dataWord ( 0 )));
2006-08-26 11:35:28 +00:00
} else if ( nodep -> isQuad ()) {
2008-09-03 17:40:01 -04:00
vluint64_t num = nodep -> toUQuad ();
2006-08-26 11:35:28 +00:00
if ( num < 10 ) ofp () -> printf ( "VL_ULL(%lld)" , ( long long ) num );
else ofp () -> printf ( "VL_ULL(0x%llx)" , ( long long ) num );
} else {
2008-09-04 11:03:46 -04:00
uint32_t num = nodep -> toUInt ();
2006-08-26 11:35:28 +00:00
if ( num < 10 ) puts ( cvtToStr ( num ));
2009-04-08 21:47:48 -04:00
else ofp () -> printf ( "0x%llx" , ( long long ) num );
2006-08-26 11:35:28 +00:00
//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 ;
2008-11-17 17:13:57 -05:00
m_splitSize = 0 ;
m_splitFilenum = 0 ;
2006-08-26 11:35:28 +00:00
}
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)
//---------------------------------------
// 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 ;
2007-04-18 18:26:38 +00:00
if ( v3Global . opt . lintOnly ()) {
// Unfortunately we have some lint checks here, so we can't just skip processing.
// We should move them to a different stage.
string filename = "/dev/null" ;
newCFile ( filename , slow , source );
ofp = new V3OutSpFile ( filename );
}
else if ( optSystemPerl ()) {
2006-08-26 11:35:28 +00:00
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 * ) {
2008-11-17 17:13:57 -05:00
if ( nodep -> funcType (). isTrace ()) {
return ; // TRACE_* handled specially
2006-08-26 11:35:28 +00:00
}
if ( ! ( nodep -> slow () ? m_slow : m_fast )) return ;
m_blkChangeDetVec . clear ();
2008-11-17 17:13:57 -05:00
splitSizeInc ( nodep );
2006-08-26 11:35:28 +00:00
puts ( " \n " );
puts ( nodep -> rtnTypeVoid ()); puts ( " " );
puts ( modClassName ( m_modp ) + "::" + nodep -> name ()
+ "(" + cFuncArgs ( nodep ) + ") { \n " );
2008-06-09 21:25:10 -04:00
puts ( "VL_DEBUG_IF(cout<< \" " );
2006-08-26 11:35:28 +00:00
for ( int i = 0 ; i < m_modp -> level (); i ++ ) { puts ( " " ); }
puts ( modClassName ( m_modp ) + "::" + nodep -> name ()
2006-08-30 22:00:55 +00:00
+ " \" <<endl; ); \n " );
2006-08-26 11:35:28 +00:00
2006-08-30 21:07:55 +00:00
if ( nodep -> symProlog ()) puts ( EmitCBaseVisitor :: symTopAssign () + " \n " );
2006-08-26 11:35:28 +00:00
if ( nodep -> initsp ()) puts ( "// Variables \n " );
2006-08-29 00:58:48 +00:00
ofp () -> putAlign ( V3OutFile :: AL_AUTO , 4 );
2006-08-26 11:35:28 +00: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 00:58:48 +00:00
ofp () -> putAlign ( V3OutFile :: AL_AUTO , 4 );
2006-08-26 11:35:28 +00:00
emitVarList ( nodep -> stmtsp (), EVL_ALL , "" );
2006-08-29 00:58:48 +00:00
ofp () -> putAlign ( V3OutFile :: AL_AUTO , 4 );
2006-08-26 11:35:28 +00: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 );");
2007-01-31 21:49:13 +00:00
for ( vector < AstChangeDet *>:: iterator it = m_blkChangeDetVec . begin ();
it != m_blkChangeDetVec . end (); ++ it ) {
AstChangeDet * nodep = * it ;
if ( nodep -> lhsp ()) {
puts ( "VL_DEBUG_IF( if(__req && (" );
bool gotOneIgnore = false ;
doubleOrDetect ( nodep , gotOneIgnore );
string varname ;
if ( nodep -> lhsp () -> castVarRef ()) {
varname = ": " + nodep -> lhsp () -> castVarRef () -> varp () -> prettyName ();
}
puts ( ")) cout<< \"\t CHANGE: " + nodep -> fileline () -> ascii ()
2008-11-19 16:44:51 -05:00
+ varname + " \" <<endl; ); \n " );
2007-01-31 21:49:13 +00:00
}
}
2006-08-26 11:35:28 +00:00
}
}
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 17:27:53 +00:00
void emitCtorImp ( AstModule * modp );
void emitConfigureImp ( AstModule * modp );
2006-08-26 11:35:28 +00:00
void emitCoverageDecl ( AstModule * modp );
2006-08-30 01:14:29 +00:00
void emitCoverageImp ( AstModule * modp );
2006-08-30 17:27:53 +00:00
void emitDestructorImp ( AstModule * modp );
2006-08-26 11:35:28 +00:00
void emitTextSection ( AstType type );
void emitIntFuncDecls ( AstModule * modp );
// High level
void emitImp ( AstModule * modp );
void emitStaticDecl ( AstModule * modp );
void emitWrapEval ( AstModule * modp );
void emitInt ( AstModule * modp );
void writeMakefile ( string filename );
public :
EmitCImp () {
m_modp = NULL ;
}
virtual ~ EmitCImp () {}
void main ( AstModule * modp , bool slow , bool fast );
void mainDoFunc ( AstCFunc * nodep ) {
nodep -> accept ( * this );
}
};
//######################################################################
// Internal EmitCStmts
void EmitCStmts :: emitVarDecl ( AstVar * nodep , const string & prefixIfImp ) {
if ( nodep -> isIO ()) {
if ( nodep -> isSc ()) {
m_ctorVarsVec . push_back ( nodep );
2006-08-29 00:58:48 +00:00
ofp () -> putAlign ( nodep -> isStatic (), 4 ); // sc stuff is a structure, so bigger alignment
2006-08-26 11:35:28 +00:00
if ( nodep -> attrScClocked () && nodep -> isInput ()) {
puts ( "sc_in_clk \t " );
} else {
2006-09-25 20:40:52 +00:00
if ( nodep -> isInout ()) puts ( "sc_inout<" );
2006-08-26 11:35:28 +00:00
else if ( nodep -> isInput ()) puts ( "sc_in<" );
else if ( nodep -> isOutput ()) puts ( "sc_out<" );
else nodep -> v3fatalSrc ( "Unknown type" );
2006-10-05 14:53:17 +00:00
puts ( nodep -> scType ());
2006-08-26 11:35:28 +00:00
puts ( "> \t " );
}
puts ( nodep -> name ());
puts ( "; \n " );
} else { // C++ signals
2006-08-29 00:58:48 +00:00
ofp () -> putAlign ( nodep -> isStatic (), nodep -> widthAlignBytes ());
2006-09-25 20:40:52 +00:00
if ( nodep -> isInout ()) puts ( "VL_INOUT" );
2006-08-26 11:35:28 +00:00
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 00:58:48 +00:00
ofp () -> putAlign ( nodep -> isStatic (), nodep -> widthAlignBytes (), nodep -> arrayElements () * nodep -> widthAlignBytes ());
if ( nodep -> isStatic () && prefixIfImp == "" ) puts ( "static " );
2006-08-29 12:01:02 +00:00
if ( nodep -> isStatic ()) puts ( "VL_ST_" ); else puts ( "VL_" );
2006-08-26 11:35:28 +00:00
if ( nodep -> widthMin () <= 8 ) {
2006-08-29 12:01:02 +00:00
puts ( "SIG8(" );
2006-08-26 11:35:28 +00:00
} else if ( nodep -> widthMin () <= 16 ) {
2006-08-29 12:01:02 +00:00
puts ( "SIG16(" );
2006-08-26 11:35:28 +00:00
} else if ( nodep -> isQuad ()) {
2006-08-29 12:01:02 +00:00
puts ( "SIG64(" );
2006-08-26 11:35:28 +00:00
} else if ( ! nodep -> isWide ()) {
2006-08-29 12:01:02 +00:00
puts ( "SIG(" );
2006-08-26 11:35:28 +00:00
} else {
2006-08-29 12:01:02 +00:00
puts ( "SIGW(" );
2006-08-26 11:35:28 +00: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 " );
2009-05-08 13:16:19 -04:00
puts (( * it ) -> name ());
puts ( "(" ); putsQuoted (( * it ) -> name ()); puts ( ")" );
2006-08-26 11:35:28 +00:00
}
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 ;
}
2008-06-29 20:02:24 -04:00
void EmitCStmts :: emitOpName ( AstNode * nodep , const string & format ,
AstNode * lhsp , AstNode * rhsp , AstNode * thsp ) {
// Look at emitOperator() format for term/uni/dual/triops,
// and write out appropriate text.
// %n* node
// %nq emitIQW on the [node]
// %nw width in bits
// %nW width in words
// %ni iterate
// %l* lhsp - if appropriate, then second char as above
// %r* rhsp - if appropriate, then second char as above
// %t* thsp - if appropriate, then second char as above
// %k Potential line break
// %P Wide temporary name
// , Commas suppressed if the previous field is suppressed
string nextComma ;
bool needComma = false ;
#define COMMA { if (nextComma!="") { puts(nextComma); nextComma=""; } }
putbs ( "" );
for ( string :: const_iterator pos = format . begin (); pos != format . end (); ++ pos ) {
if ( pos [ 0 ] == ',' ) {
// Remember we need to add one, but don't do yet to avoid ",)"
if ( needComma ) {
if ( pos [ 1 ] == ' ' ) { nextComma = ", " ; }
else nextComma = "," ;
needComma = false ;
}
if ( pos [ 1 ] == ' ' ) { ++ pos ; } // Must do even if no nextComma
}
else if ( pos [ 0 ] == '%' ) {
++ pos ;
bool detail = false ;
AstNode * detailp = NULL ;
switch ( pos [ 0 ]) {
case '%' : puts ( "%" ); break ;
case 'k' : putbs ( "" ); break ;
case 'n' : detail = true ; detailp = nodep ; break ;
case 'l' : detail = true ; detailp = lhsp ; break ;
case 'r' : detail = true ; detailp = rhsp ; break ;
case 't' : detail = true ; detailp = thsp ; break ;
case 'P' :
if ( nodep -> isWide ()) {
if ( ! m_wideTempRefp ) nodep -> v3fatalSrc ( "Wide Op w/ no temp, perhaps missing op in V3EmitC?" );
COMMA ;
puts ( m_wideTempRefp -> hiername ());
puts ( m_wideTempRefp -> varp () -> name ());
m_wideTempRefp = NULL ;
needComma = true ;
}
break ;
default :
nodep -> v3fatalSrc ( "Unknown emitOperator format code: %" << pos [ 0 ]);
break ;
}
if ( detail ) {
// Get next letter of %[nlrt]
++ pos ;
switch ( pos [ 0 ]) {
case 'q' : emitIQW ( detailp ); break ;
case 'w' :
COMMA ;
puts ( cvtToStr ( detailp -> widthMin ()));
needComma = true ;
break ;
case 'W' :
if ( lhsp -> isWide ()) {
COMMA ;
puts ( cvtToStr ( lhsp -> widthWords ()));
needComma = true ;
}
break ;
case 'i' :
COMMA ;
if ( ! detailp ) { nodep -> v3fatalSrc ( "emitOperator() references undef node" ); }
else detailp -> iterateAndNext ( * this );
needComma = true ;
break ;
default :
nodep -> v3fatalSrc ( "Unknown emitOperator format code: %[nlrt]" << pos [ 0 ]);
break ;
}
}
} else {
// Normal text
if ( pos [ 0 ] == ')' ) nextComma = "" ;
COMMA ;
string s ; s += pos [ 0 ]; puts ( s );
2006-08-26 11:35:28 +00:00
}
}
}
//----------------------------------------------------------------------
// Mid level - VISITS
// We only do one display at once, so can just use static state
struct EmitDispState {
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_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 ;
2008-07-01 14:15:10 -04:00
void EmitCStmts :: displayEmit ( AstNode * nodep , bool isScan ) {
if ( emitDispState . m_format == ""
&& nodep -> castDisplay ()) { // not fscanf etc, as they need to return value
// NOP
} else {
2006-08-26 11:35:28 +00:00
// Format
2008-07-01 14:15:10 -04:00
bool isStmt ;
if ( AstFScanF * dispp = nodep -> castFScanF ()) {
isStmt = false ;
puts ( "VL_FSCANF_IX(" );
dispp -> filep () -> iterate ( * this );
puts ( "," );
} else if ( AstSScanF * dispp = nodep -> castSScanF ()) {
isStmt = false ;
checkMaxWords ( dispp -> fromp ());
puts ( "VL_SSCANF_I" ); emitIQW ( dispp -> fromp ()); puts ( "X(" );
puts ( cvtToStr ( dispp -> fromp () -> widthMin ()));
puts ( "," );
dispp -> fromp () -> iterate ( * this );
puts ( "," );
} else if ( AstDisplay * dispp = nodep -> castDisplay ()) {
isStmt = true ;
if ( dispp -> filep ()) {
puts ( "VL_FWRITEF(" );
dispp -> filep () -> iterate ( * this );
puts ( "," );
} else {
puts ( "VL_WRITEF(" );
}
2006-08-26 11:35:28 +00:00
} else {
2008-07-01 14:15:10 -04:00
isStmt = true ;
nodep -> v3fatalSrc ( "Unknown displayEmit node type" );
2006-08-26 11:35:28 +00:00
}
2008-07-01 14:15:10 -04:00
puts ( " \" " );
2009-05-08 13:16:19 -04:00
ofp () -> putsNoTracking ( emitDispState . m_format ); // Not putsQuoted - already contains \s
2006-08-26 11:35:28 +00:00
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 );
2008-07-01 14:15:10 -04:00
if ( argp ) {
if ( isScan ) puts ( "&(" );
argp -> iterate ( * this );
if ( isScan ) puts ( ")" );
}
2006-08-26 11:35:28 +00:00
ofp () -> indentDec ();
}
// End
2008-07-01 14:15:10 -04:00
puts ( ")" );
if ( isStmt ) puts ( "; \n " );
else puts ( " " );
2006-08-26 11:35:28 +00:00
// Prep for next
emitDispState . clear ();
}
}
2008-07-01 14:15:10 -04:00
void EmitCStmts :: displayArg ( AstNode * dispp , AstNode ** elistp , bool isScan ,
string vfmt , char fmtLetter ) {
2006-08-26 11:35:28 +00:00
// Print display argument, edits elistp
2008-06-30 14:31:58 -04:00
AstNode * argp = * elistp ;
if ( ! argp ) {
// expectDisplay() checks this first, so internal error if found here
dispp -> v3error ( "Internal: Missing arguments for $display format" );
2006-08-26 11:35:28 +00:00
return ;
}
2008-06-30 14:31:58 -04:00
if ( argp -> widthMin () > VL_VALUE_STRING_MAX_WIDTH ) {
2006-08-26 11:35:28 +00:00
dispp -> v3error ( "Exceeded limit of 1024 bits for any display arguments" );
}
2008-06-30 14:31:58 -04:00
if ( argp && argp -> isWide ()
&& ( fmtLetter == 'd' || fmtLetter == 'u' )) {
2008-07-01 14:15:10 -04:00
argp -> v3error ( "Unsupported: " << dispp -> verilogKwd () << " of dec format of > 64 bit results (use hex format instead)" );
2008-06-30 14:31:58 -04:00
}
if ( argp && argp -> widthMin () > 8 && fmtLetter == 'c' ) {
// Technically legal, but surely not what the user intended.
2008-07-01 14:15:10 -04:00
argp -> v3error ( dispp -> verilogKwd () << " of char format of > 8 bit result" );
2008-06-30 14:31:58 -04:00
}
2006-08-26 11:35:28 +00:00
2008-06-30 14:31:58 -04:00
//string pfmt = "%"+displayFormat(argp, vfmt, fmtLetter)+fmtLetter;
string pfmt ;
2008-08-05 14:45:20 -04:00
if (( fmtLetter == 'u' || fmtLetter == 'd' || fmtLetter == 't' )
2008-07-01 14:15:10 -04:00
&& ! isScan
2008-06-30 14:31:58 -04:00
&& vfmt == "" ) { // Size decimal output. Spec says leading spaces, not zeros
double mantissabits = argp -> 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 );
pfmt = string ( "%" ) + cvtToStr ( nchars ) + fmtLetter ;
2006-08-26 11:35:28 +00:00
} else {
2008-06-30 14:31:58 -04:00
pfmt = string ( "%" ) + vfmt + fmtLetter ;
2006-08-26 11:35:28 +00:00
}
2008-06-30 14:31:58 -04:00
emitDispState . pushFormat ( pfmt );
emitDispState . pushArg ( NULL , cvtToStr ( argp -> widthMin ()));
emitDispState . pushArg ( argp , "" );
2006-08-26 11:35:28 +00:00
// Next parameter
* elistp = ( * elistp ) -> nextp ();
}
2008-07-01 14:15:10 -04:00
void EmitCStmts :: displayNode ( AstNode * nodep , const string & vformat , AstNode * exprsp ,
bool isScan ) {
AstNode * elistp = exprsp ;
2006-08-26 11:35:28 +00:00
// Convert Verilog display to C printf formats
// "%0t" becomes "%d"
emitDispState . clear ();
2008-06-30 14:31:58 -04:00
string vfmt = "" ;
2008-07-01 14:15:10 -04:00
string :: const_iterator pos = vformat . begin ();
2006-08-26 11:35:28 +00:00
bool inPct = false ;
for (; pos != vformat . end (); ++ pos ) {
2008-06-30 14:31:58 -04:00
//UINFO(1,"Parse '"<<*pos<<"' IP"<<inPct<<" List "<<(void*)(elistp)<<endl);
if ( ! inPct && pos [ 0 ] == '%' ) {
2006-08-26 11:35:28 +00:00
inPct = true ;
2008-06-30 14:31:58 -04:00
vfmt = "" ;
2006-08-26 11:35:28 +00:00
} else if ( ! inPct ) { // Normal text
emitDispState . pushFormat ( * pos );
} else { // Format character
2008-06-30 14:31:58 -04:00
inPct = false ;
switch ( tolower ( pos [ 0 ])) {
case '0' : case '1' : case '2' : case '3' : case '4' :
case '5' : case '6' : case '7' : case '8' : case '9' :
2006-08-26 11:35:28 +00:00
// Digits, like %5d, etc.
2008-06-30 14:31:58 -04:00
vfmt += pos [ 0 ];
inPct = true ; // Get more digits
break ;
case '%' :
emitDispState . pushFormat ( "%%" ); // We're printf'ing it, so need to quote the %
break ;
// Special codes
2008-07-01 14:15:10 -04:00
case '~' : displayArg ( nodep , & elistp , isScan , vfmt , 'd' ); break ; // Signed decimal
2008-06-30 14:31:58 -04:00
// Spec: h d o b c l
2008-07-01 14:15:10 -04:00
case 'b' : displayArg ( nodep , & elistp , isScan , vfmt , 'b' ); break ;
case 'c' : displayArg ( nodep , & elistp , isScan , vfmt , 'c' ); break ;
2008-08-05 14:45:20 -04:00
case 't' : displayArg ( nodep , & elistp , isScan , vfmt , 't' ); break ;
2008-07-01 14:15:10 -04:00
case 'd' : displayArg ( nodep , & elistp , isScan , vfmt , 'u' ); break ; // Unsigned decimal
case 'o' : displayArg ( nodep , & elistp , isScan , vfmt , 'o' ); break ;
2008-06-30 14:31:58 -04:00
case 'h' :
2008-07-01 14:15:10 -04:00
case 'x' : displayArg ( nodep , & elistp , isScan , vfmt , 'x' ); break ;
case 's' : displayArg ( nodep , & elistp , isScan , vfmt , 's' ); break ;
2008-06-30 14:31:58 -04:00
case 'm' : {
emitDispState . pushFormat ( "%S" );
emitDispState . pushArg ( NULL , "vlSymsp->name()" );
2008-07-01 14:15:10 -04:00
if ( ! nodep -> castDisplay ()) nodep -> v3fatalSrc ( "Non-Display with %m" );
AstScopeName * scopenamep = nodep -> castDisplay () -> scopeNamep ();
if ( ! scopenamep ) nodep -> v3fatalSrc ( "Display with %m but no AstScopeName" );
for ( AstText * textp = scopenamep -> scopeAttrp (); textp ; textp = textp -> nextp () -> castText ()) {
2008-06-30 14:31:58 -04:00
emitDispState . pushFormat ( textp -> text ());
2006-08-26 11:35:28 +00:00
}
2008-06-30 14:31:58 -04:00
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 ;
2006-08-26 11:35:28 +00:00
}
}
}
if ( elistp != NULL ) {
2008-06-30 14:31:58 -04:00
// expectFormat also checks this, and should have found it first, so internal
elistp -> v3error ( "Internal: Extra arguments for $display format \n " );
2006-08-26 11:35:28 +00:00
}
2008-07-01 14:15:10 -04:00
displayEmit ( nodep , isScan );
2006-08-26 11:35:28 +00:00
}
//######################################################################
// Internal EmitC
void EmitCImp :: emitVarResets ( AstModule * modp ) {
puts ( "// Reset internal values \n " );
if ( modp -> isTop ()) {
2006-08-29 00:27:04 +00:00
if ( v3Global . opt . inhibitSim ()) puts ( "__Vm_inhibitSim = false; \n " );
2006-08-26 11:35:28 +00: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 ) {
2008-12-05 10:54:14 -05:00
if ( v3Global . opt . coverage ()) {
2006-08-26 11:35:28 +00:00
ofp () -> putsPrivate ( true );
puts ( "// Coverage \n " );
2008-12-12 16:04:56 -05:00
puts ( "void __vlCoverInsert(uint32_t* countp, bool enable, const char* filenamep, int lineno, int column, \n " );
puts ( "const char* hierp, const char* pagep, const char* commentp); \n " );
2006-08-30 01:14:29 +00:00
}
}
2006-08-30 17:27:53 +00: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 ) {
2008-12-05 10:54:14 -05:00
puts ( " \n void " + modClassName ( modp ) + "::__Vconfigure(" + symClassName () + "* vlSymsp, bool first) { \n " );
puts ( "if (0 && first) {} // Prevent unused \n " );
puts ( "this->__VlSymsp = vlSymsp; \n " ); // First, as later stuff needs it.
2006-08-30 17:27:53 +00:00
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 01:14:29 +00:00
void EmitCImp :: emitCoverageImp ( AstModule * modp ) {
2008-12-05 10:54:14 -05:00
if ( v3Global . opt . coverage () ) {
2006-08-30 01:14:29 +00:00
puts ( " \n // Coverage \n " );
2007-11-30 22:12:53 +00:00
// Rather than putting out SP_COVER_INSERT calls directly, we do it via this function
2006-08-26 11:35:28 +00:00
// This gets around gcc slowness constructing all of the template arguments
2008-12-05 10:54:14 -05:00
// SystemPerl 1.301 is much faster, but it's nice to remain back
// compatible, and have a common wrapper.
2008-12-12 16:04:56 -05:00
puts ( "void " + modClassName ( m_modp ) + "::__vlCoverInsert(uint32_t* countp, bool enable, const char* filenamep, int lineno, int column, \n " );
puts ( "const char* hierp, const char* pagep, const char* commentp) { \n " );
2008-12-05 10:54:14 -05:00
puts ( "static uint32_t fake_zero_count = 0; \n " );
puts ( "if (!enable) countp = &fake_zero_count; \n " ); // Used for second++ instantiation of identical bin
puts ( "*countp = 0; \n " );
2006-08-26 11:35:28 +00:00
puts ( "SP_COVER_INSERT(countp," );
2008-12-12 16:04:56 -05:00
puts ( " \" filename \" ,filenamep," );
2006-08-26 11:35:28 +00:00
puts ( " \" lineno \" ,lineno," );
puts ( " \" column \" ,column, \n " );
2008-12-12 16:04:56 -05:00
//puts( "\"hier\",string(__VlSymsp->name())+hierp,"); // Need to move hier into scopes and back out if do this
puts ( " \" hier \" ,string(name())+hierp," );
puts ( " \" page \" ,pagep," );
puts ( " \" comment \" ,commentp); \n " );
2006-08-26 11:35:28 +00:00
puts ( "} \n " );
}
}
2006-08-30 17:27:53 +00: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 11:35:28 +00: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 ())
2009-05-08 13:16:19 -04:00
+ " " );
ofp () -> putsQuoted ( nodep -> fileline () -> filename ());
ofp () -> putsNoTracking ( " \n " );
2006-08-26 11:35:28 +00:00
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 01:14:29 +00:00
// Must be before other constructors, as __vlCoverInsert calls it
2006-08-30 21:07:55 +00:00
puts ( EmitCBaseVisitor :: symClassVar () + " = __VlSymsp = new " + symClassName () + "(this, name()); \n " );
puts ( EmitCBaseVisitor :: symTopAssign () + " \n " );
2006-08-26 11:35:28 +00: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 ())) {
2008-12-03 10:11:28 -05:00
puts ( "sensitive << " + varp -> name () + "; \n " );
2006-08-26 11:35:28 +00:00
}
}
}
puts ( " \n " );
}
}
void EmitCImp :: emitWrapEval ( AstModule * modp ) {
puts ( " \n void " + modClassName ( modp ) + "::eval() { \n " );
2006-08-30 21:07:55 +00:00
puts ( EmitCBaseVisitor :: symClassVar () + " = this->__VlSymsp; // Setup global symbol table \n " );
puts ( EmitCBaseVisitor :: symTopAssign () + " \n " );
2006-08-26 11:35:28 +00:00
puts ( "// Initialize \n " );
2006-08-30 21:07:55 +00:00
puts ( "if (VL_UNLIKELY(!vlSymsp->__Vm_didInit)) _eval_initial_loop(vlSymsp); \n " );
2006-08-29 00:27:04 +00:00
if ( v3Global . opt . inhibitSim ()) {
2006-08-30 21:07:55 +00:00
puts ( "if (VL_UNLIKELY(__Vm_inhibitSim)) return; \n " );
2006-08-29 00:27:04 +00:00
}
2006-08-26 11:35:28 +00: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 21:07:55 +00:00
puts ( "IData __Vchange=1; \n " );
puts ( "while (VL_LIKELY(__Vchange)) { \n " );
2006-08-26 11:35:28 +00:00
puts ( "VL_DEBUG_IF(cout<< \" Clock loop \" <<endl;); \n " );
#endif
2006-08-30 21:07:55 +00:00
puts ( "vlSymsp->__Vm_activity = true; \n " );
puts ( "_eval(vlSymsp); \n " );
2006-08-26 11:35:28 +00:00
#ifndef NEW_ORDERING
2006-08-30 21:07:55 +00:00
puts ( "__Vchange = _change_request(vlSymsp); \n " );
2006-08-26 11:35:28 +00:00
puts ( "if (++__VclockLoop > 100) vl_fatal(__FILE__,__LINE__,__FILE__, \" Verilated model didn't converge \" ); \n " );
puts ( "} \n " );
#endif
puts ( "} \n " );
//
2006-08-30 21:07:55 +00: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 11:35:28 +00:00
#ifndef NEW_ORDERING
2006-08-30 21:07:55 +00:00
puts ( "vlSymsp->__Vm_activity = true; \n " );
2006-08-26 11:35:28 +00:00
puts ( "int __VclockLoop = 0; \n " );
2006-08-30 21:07:55 +00:00
puts ( "IData __Vchange=1; \n " );
puts ( "while (VL_LIKELY(__Vchange)) { \n " );
2006-08-26 11:35:28 +00:00
#endif
2006-08-30 21:07:55 +00:00
puts ( "_eval_settle(vlSymsp); \n " );
puts ( "_eval(vlSymsp); \n " );
2006-08-26 11:35:28 +00:00
#ifndef NEW_ORDERING
2006-08-30 21:07:55 +00:00
puts ( "__Vchange = _change_request(vlSymsp); \n " );
2006-08-26 11:35:28 +00: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 15:27:15 +00:00
// in order of 0:clocks, 1:vluint8, 2:vluint16, 4:vluint32, 5:vluint64, 6:wide, 7:arrays
2006-08-26 11:35:28 +00:00
// This aids cache packing and locality
2006-08-29 00:58:48 +00: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 ;
2009-06-09 15:37:52 -04:00
case EVL_TEMP : doit = ( varp -> isTemp () && ! varp -> isIO ()); break ;
2006-08-29 00:58:48 +00:00
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 ;
2009-03-13 14:17:30 -04:00
else if ( varp -> isScBv ()) sigbytes = 6 ;
2006-08-29 00:58:48 +00:00
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 11:35:28 +00:00
}
}
}
}
2006-08-29 00:58:48 +00:00
ofp () -> putAlign ( isstatic , 4 , 0 , prefixIfImp . c_str ());
2006-08-26 11:35:28 +00: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 12:01:02 +00:00
if ( funcp -> isStatic ()) puts ( "static " );
2006-08-26 11:35:28 +00: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 " );
2007-11-30 22:38:21 +00:00
}
if ( v3Global . needHInlines ()) { // Set by V3EmitCInlines; should have been called before us
puts ( "#include \" " + topClassName () + "__Inlines.h \"\n " );
2006-08-26 11:35:28 +00:00
}
// 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 " );
}
}
2008-01-15 18:36:47 +00:00
if ( v3Global . opt . trace ()) {
if ( optSystemPerl ()) {
puts ( "class SpTraceVcd; \n " );
} else {
puts ( "class SpTraceVcdCFile; \n " );
}
}
2006-08-26 11:35:28 +00:00
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 00:58:48 +00:00
ofp () -> putAlign ( V3OutFile :: AL_AUTO , 8 );
2006-08-26 11:35:28 +00:00
puts ( symClassName () + "* \t __VlSymsp; \t\t // Symbol table \n " );
ofp () -> putsPrivate ( false ); // public:
if ( modp -> isTop ()) {
2006-08-29 00:27:04 +00:00
if ( v3Global . opt . inhibitSim ()) {
2006-08-29 00:58:48 +00:00
ofp () -> putAlign ( V3OutFile :: AL_AUTO , sizeof ( bool ));
2006-08-29 00:27:04 +00:00
puts ( "bool \t __Vm_inhibitSim; \t ///< Set true to disable evaluation of module \n " );
}
2006-08-26 11:35:28 +00:00
}
2006-08-29 00:58:48 +00:00
ofp () -> putAlign ( V3OutFile :: AL_AUTO , 8 );
2006-08-26 11:35:28 +00:00
emitCoverageDecl ( modp ); // may flip public/private
2006-08-29 00:58:48 +00:00
ofp () -> putAlign ( V3OutFile :: AL_AUTO , 8 );
2006-08-26 11:35:28 +00: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.
2009-03-13 14:17:30 -04:00
if ( varp -> isWide ()) { // Unsupported for output
2006-08-26 11:35:28 +00:00
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 21:07:55 +00: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 11:35:28 +00:00
ofp () -> putsPrivate ( false ); // public:
if ( optSystemC () && modp -> isTop ()) {
puts ( "SC_CTOR(" + modClassName ( modp ) + "); \n " );
2006-08-30 17:27:53 +00:00
puts ( "virtual ~" + modClassName ( modp ) + "(); \n " );
2006-08-26 11:35:28 +00:00
} else if ( optSystemC ()) {
puts ( "VL_CTOR(" + modClassName ( modp ) + "); \n " );
2006-08-30 17:27:53 +00:00
puts ( "~" + modClassName ( modp ) + "(); \n " );
2006-08-26 11:35:28 +00:00
} else {
puts ( modClassName ( modp ) + "(const char* name= \" TOP \" ); \n " );
2006-08-30 17:27:53 +00:00
puts ( "~" + modClassName ( modp ) + "(); \n " );
2007-12-13 13:54:04 +00:00
}
if ( v3Global . opt . trace () && ! optSystemPerl ()) {
puts ( "void \t trace (SpTraceVcdCFile* tfp, int levels, int options=0); \n " );
2006-08-26 11:35:28 +00:00
}
2008-12-05 10:54:14 -05:00
puts ( "void \t __Vconfigure(" + symClassName () + "* symsp, bool first); \n " );
2006-08-26 11:35:28 +00: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 00:27:04 +00: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 11:35:28 +00:00
ofp () -> putsPrivate ( true ); // private:
2006-08-30 22:00:55 +00:00
puts ( "static void _eval_initial_loop(" + EmitCBaseVisitor :: symClassVar () + "); \n " );
2006-08-26 11:35:28 +00:00
}
emitIntFuncDecls ( modp );
if ( ! optSystemPerl () && v3Global . opt . trace ()) {
ofp () -> putsPrivate ( false ); // public:
2006-08-30 22:00:55 +00: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 11:35:28 +00:00
}
2006-08-30 22:00:55 +00:00
puts ( "} VL_ATTR_ALIGNED(64); \n " );
2006-08-26 11:35:28 +00: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 21:07:55 +00:00
puts ( "#include \" " + symClassName () + ".h \"\n " );
2006-08-26 11:35:28 +00:00
2008-11-17 17:13:57 -05:00
if ( optSystemPerl () && ( splitFilenum () || ! m_fast )) {
2006-08-26 11:35:28 +00:00
puts ( " \n " );
puts ( "SP_MODULE_CONTINUED(" + modClassName ( modp ) + "); \n " );
}
emitTextSection ( AstType :: SCIMPHDR );
2006-08-29 00:58:48 +00:00
2008-11-17 17:13:57 -05:00
if ( m_slow && splitFilenum () == 0 ) {
2006-08-29 00:58:48 +00:00
puts ( " \n //-------------------- \n " );
puts ( "// STATIC VARIABLES \n\n " );
emitVarList ( modp -> stmtsp (), EVL_ALL , modClassName ( modp ));
}
2008-11-17 17:13:57 -05:00
if ( m_fast && splitFilenum () == 0 ) {
2006-08-26 11:35:28 +00:00
emitTextSection ( AstType :: SCIMP );
emitStaticDecl ( modp );
}
2008-11-17 17:13:57 -05:00
if ( m_slow && splitFilenum () == 0 ) {
2006-08-26 11:35:28 +00:00
puts ( " \n //-------------------- \n " );
2006-08-30 17:27:53 +00:00
emitCtorImp ( modp );
emitConfigureImp ( modp );
emitDestructorImp ( modp );
2006-08-30 01:14:29 +00:00
emitCoverageImp ( modp );
2006-08-26 11:35:28 +00:00
}
2006-08-30 17:27:53 +00:00
2008-11-17 17:13:57 -05:00
if ( m_fast && splitFilenum () == 0 ) {
2006-08-26 11:35:28 +00:00
if ( modp -> isTop ()) {
emitStaticDecl ( modp );
puts ( " \n //-------------------- \n " );
puts ( " \n " );
emitWrapEval ( modp );
}
}
2008-11-17 17:13:57 -05:00
if ( m_fast && splitFilenum () == 0 ) {
2007-12-13 13:54:04 +00:00
if ( v3Global . opt . trace () && optSystemPerl () && m_modp -> isTop ()) {
2006-08-26 11:35:28 +00:00
puts ( " \n " );
puts ( " \n /*AUTOTRACE(__MODULE__,recurse,activity,exists)*/ \n\n " );
}
}
// Blocks
puts ( " \n //-------------------- \n " );
puts ( "// Internal Methods \n " );
}
//######################################################################
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 ) {
2009-01-21 16:56:50 -05:00
UINFO ( 0 , " Emitting " << modClassName ( modp ) << endl );
2006-08-26 11:35:28 +00:00
}
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 );
2008-06-09 21:25:10 -04:00
2006-08-26 11:35:28 +00:00
for ( AstNode * nodep = modp -> stmtsp (); nodep ; nodep = nodep -> nextp ()) {
if ( AstCFunc * funcp = nodep -> castCFunc ()) {
2008-11-17 17:13:57 -05:00
if ( splitNeeded ()) {
2006-08-26 11:35:28 +00:00
// Close old file
delete m_ofp ; m_ofp = NULL ;
// Open a new file
2008-11-17 17:13:57 -05:00
m_ofp = newOutCFile ( modp , ! m_fast , true /*source*/ , splitFilenumInc ());
2006-08-26 11:35:28 +00:00
emitImp ( modp );
}
mainDoFunc ( funcp );
}
}
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
2008-11-17 17:13:57 -05:00
2006-08-26 11:35:28 +00:00
// METHODS
2008-11-17 17:13:57 -05:00
void newOutCFile ( int filenum ) {
string filename = ( v3Global . opt . makeDir () + "/" + topClassName ()
+ ( m_slow ? "__Trace__Slow" : "__Trace" ));
if ( filenum ) filename += "__" + cvtToStr ( filenum );
filename += ".cpp" ;
AstCFile * cfilep = newCFile ( filename , m_slow , true /*source*/ );
cfilep -> support ( true );
if ( m_ofp ) v3fatalSrc ( "Previous file not closed" );
m_ofp = new V3OutCFile ( filename );
m_ofp -> putsHeader ();
emitTraceHeader ();
}
2006-08-26 11:35:28 +00:00
void emitTraceHeader () {
// Includes
2007-12-13 13:54:04 +00:00
if ( optSystemPerl ()) {
2006-08-26 11:35:28 +00:00
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 (" );
2007-12-13 13:54:04 +00:00
if ( optSystemPerl ()) {
2006-08-26 11:35:28 +00:00
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 21:07:55 +00:00
puts ( EmitCBaseVisitor :: symClassVar () + " = t->__VlSymsp; // Setup global symbol table \n " );
2006-08-26 11:35:28 +00:00
puts ( "if (!Verilated::calcUnusedSigs()) vl_fatal(__FILE__,__LINE__,__FILE__, \" Turning on wave traces requires Verilated::traceEverOn(true) call before time 0. \" ); \n " );
2009-05-08 14:48:33 -04:00
//Future; need to wait to estabilish backwards compatibility
//puts("#if defined(SPTRACEVCDC_VERSION) && SPTRACEVCDC_VERSION >= 1320\n");
//puts("vcdp->scopeEscape(' ');\n");
2006-08-30 21:07:55 +00:00
puts ( "t->traceInitThis (vlSymsp, vcdp, code); \n " );
2009-05-08 14:48:33 -04:00
//puts("vcdp->scopeEscape('.');\n"); // Restore so SystemPerl traced files won't break
2006-08-26 11:35:28 +00:00
puts ( "} \n " );
2008-06-09 21:25:10 -04:00
2006-08-26 11:35:28 +00:00
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 21:07:55 +00:00
puts ( EmitCBaseVisitor :: symClassVar () + " = t->__VlSymsp; // Setup global symbol table \n " );
puts ( "t->traceFullThis (vlSymsp, vcdp, code); \n " );
2006-08-26 11:35:28 +00: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 21:07:55 +00: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 11:35:28 +00:00
puts ( "} \n " );
puts ( "} \n " );
puts ( " \n //====================== \n\n " );
}
2009-03-13 14:17:30 -04:00
bool emitTraceIsScBv ( AstTraceInc * nodep ) {
2006-08-26 11:35:28 +00:00
AstVarRef * varrefp = nodep -> valuep () -> castVarRef ();
if ( ! varrefp ) return false ;
AstVar * varp = varrefp -> varp ();
2009-03-13 14:17:30 -04:00
return varp -> isSc () && varp -> isScBv ();
2006-08-26 11:35:28 +00:00
}
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 ()));
2009-05-08 13:16:19 -04:00
puts ( "," );
putsQuoted ( nodep -> showname ());
2006-08-26 11:35:28 +00:00
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 );
2008-11-17 17:13:57 -05:00
string full = (( m_funcp -> funcType () == AstCFuncType :: TRACE_FULL
|| m_funcp -> funcType () == AstCFuncType :: TRACE_FULL_SUB )
? "full" : "chg" );
2009-03-13 14:17:30 -04:00
if ( nodep -> isWide () || emitTraceIsScBv ( nodep )) {
2006-08-26 11:35:28 +00:00
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 ();
2009-03-13 14:17:30 -04:00
if ( emitTraceIsScBv ( nodep )) puts ( "(uint32_t*)" );
2006-08-26 11:35:28 +00:00
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()" );
2009-03-13 14:17:30 -04:00
if ( emitTraceIsScBv ( nodep )) puts ( ".get_datap()" );
2006-08-26 11:35:28 +00:00
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 ;
2008-11-17 17:13:57 -05:00
if ( nodep -> funcType (). isTrace ()) { // TRACE_*
2006-08-26 11:35:28 +00:00
m_funcp = nodep ;
2008-11-17 17:13:57 -05:00
if ( splitNeeded ()) {
// Close old file
delete m_ofp ; m_ofp = NULL ;
// Open a new file
newOutCFile ( splitFilenumInc ());
}
splitSizeInc ( nodep );
2006-08-26 11:35:28 +00:00
puts ( " \n " );
puts ( nodep -> rtnTypeVoid ()); puts ( " " );
puts ( topClassName () + "::" + nodep -> name ()
+ "(" + cFuncArgs ( nodep ) + ") { \n " );
2006-08-30 22:00:55 +00:00
if ( nodep -> symProlog ()) puts ( EmitCBaseVisitor :: symTopAssign () + " \n " );
2006-08-26 11:35:28 +00:00
puts ( "int c=code; \n " );
puts ( "if (0 && vcdp && c) {} // Prevent unused \n " );
if ( nodep -> funcType () == AstCFuncType :: TRACE_INIT ) {
2006-08-30 22:00:55 +00:00
puts ( "vcdp->module(vlSymsp->name()); // Setup signal names \n " );
2008-11-17 17:13:57 -05:00
} else if ( nodep -> funcType () == AstCFuncType :: TRACE_INIT_SUB ) {
2006-08-26 11:35:28 +00:00
} else if ( nodep -> funcType () == AstCFuncType :: TRACE_FULL ) {
2008-11-17 17:13:57 -05:00
} else if ( nodep -> funcType () == AstCFuncType :: TRACE_FULL_SUB ) {
2006-08-26 11:35:28 +00:00
} else if ( nodep -> funcType () == AstCFuncType :: TRACE_CHANGE ) {
2008-11-17 17:13:57 -05:00
} else if ( nodep -> funcType () == AstCFuncType :: TRACE_CHANGE_SUB ) {
2006-08-26 11:35:28 +00:00
} else nodep -> v3fatalSrc ( "Bad Case" );
if ( nodep -> initsp ()) puts ( "// Variables \n " );
emitVarList ( nodep -> initsp (), EVL_ALL , "" );
nodep -> initsp () -> iterateAndNext ( * this );
2006-08-29 00:58:48 +00:00
ofp () -> putAlign ( V3OutFile :: AL_AUTO , 4 );
2006-08-26 11:35:28 +00:00
puts ( "// Body \n " );
puts ( "{ \n " );
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 * ) {
}
2008-06-09 21:25:10 -04:00
2006-08-26 11:35:28 +00:00
public :
EmitCTrace ( bool slow ) {
m_funcp = NULL ;
m_slow = slow ;
}
virtual ~ EmitCTrace () {}
void main () {
// Put out the file
2008-11-17 17:13:57 -05:00
newOutCFile ( 0 );
2006-08-26 11:35:28 +00:00
if ( m_slow ) emitTraceSlow ();
else emitTraceFast ();
v3Global . rootp () -> accept ( * this );
2008-11-17 17:13:57 -05:00
delete m_ofp ; m_ofp = NULL ;
2006-08-26 11:35:28 +00:00
}
};
//######################################################################
// 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 (); }
}
}