2012-04-12 21:08:20 -04:00
// -*- mode: C++; c-file-style: "cc-mode" -*-
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
//
//*************************************************************************
//
2012-01-15 10:26:28 -05:00
// Copyright 2003-2012 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"
2012-04-05 21:46:55 -04:00
#define VL_VALUE_STRING_MAX_WIDTH 8192 // We use a static char array in VL_VALUE_STRING
2006-08-26 11:35:28 +00:00
//######################################################################
// 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
2011-08-04 21:58:45 -04:00
int splitFilenum () const { return m_splitFilenum ; }
2008-11-17 17:13:57 -05:00
int splitFilenumInc () { m_splitSize = 0 ; return ++ m_splitFilenum ; }
2011-08-04 21:58:45 -04:00
int splitSize () const { return m_splitSize ; }
2008-11-17 17:13:57 -05:00
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
2010-01-17 15:53:12 -05:00
void displayNode ( AstNode * nodep , AstScopeName * scopenamep ,
const string & vformat , AstNode * exprsp , bool isScan );
2008-07-01 14:15:10 -04:00
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 ) {
2010-01-16 20:30:29 -05:00
// Other abbrevs: "C"har, "S"hort, "F"loat, "D"ouble, stri"N"g
2006-08-26 11:35:28 +00:00
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
// 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 ()) {
2009-11-23 21:24:55 -05:00
puts ( "O(" );
2006-08-26 11:35:28 +00:00
} else {
2009-11-23 21:24:55 -05:00
puts ( "I(" );
2006-08-26 11:35:28 +00:00
}
puts ( cvtToStr ( nodep -> widthMin ()) + "," );
selp -> lsbp () -> iterateAndNext ( * this ); puts ( ", " );
selp -> fromp () -> iterateAndNext ( * this ); puts ( ", " );
} else {
putbs ( "VL_ASSIGNSEL_" );
emitIQW ( selp -> fromp ());
2009-11-23 21:24:55 -05:00
puts ( "II" );
2006-08-26 11:35:28 +00:00
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 ()
2011-06-28 20:45:50 -04:00
&& ! nodep -> rhsp () -> castCMath ()
2006-08-26 11:35:28 +00:00
&& ! 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 " );
}
2010-04-05 20:01:17 -04:00
virtual void visit ( AstAlwaysPublic * , AstNUser * ) {
}
2006-08-26 11:35:28 +00:00
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 * ) {
2010-01-17 15:53:12 -05:00
string text = nodep -> fmtp () -> text ();
2009-10-22 21:16:52 -04:00
if ( nodep -> addNewline ()) text += " \n " ;
2010-01-17 15:53:12 -05:00
displayNode ( nodep , nodep -> fmtp () -> scopeNamep (), text , nodep -> fmtp () -> exprsp (), false );
2008-07-01 14:15:10 -04:00
}
2009-12-05 10:38:49 -05:00
virtual void visit ( AstScopeName * nodep , AstNUser * ) {
// For use under AstCCalls for dpiImports. ScopeNames under displays are handled in AstDisplay
2009-12-20 08:27:00 -05:00
if ( ! nodep -> dpiExport ()) {
putbs ( "(&(vlSymsp->__Vscope_" + nodep -> scopeSymName () + "))" );
}
2009-12-05 10:38:49 -05:00
}
2009-11-23 21:24:55 -05:00
virtual void visit ( AstSFormat * nodep , AstNUser * ) {
2010-01-17 15:53:12 -05:00
displayNode ( nodep , nodep -> fmtp () -> scopeNamep (), nodep -> fmtp () -> text (), nodep -> fmtp () -> exprsp (), false );
2009-11-23 21:24:55 -05:00
}
2010-01-17 19:13:44 -05:00
virtual void visit ( AstSFormatF * nodep , AstNUser * ) {
displayNode ( nodep , nodep -> scopeNamep (), nodep -> text (), nodep -> exprsp (), false );
}
2008-07-01 14:15:10 -04:00
virtual void visit ( AstFScanF * nodep , AstNUser * ) {
2010-01-17 15:53:12 -05:00
displayNode ( nodep , NULL , nodep -> text (), nodep -> exprsp (), true );
2008-07-01 14:15:10 -04:00
}
virtual void visit ( AstSScanF * nodep , AstNUser * ) {
2010-01-17 15:53:12 -05:00
displayNode ( nodep , NULL , nodep -> text (), nodep -> exprsp (), true );
2008-07-01 14:15:10 -04:00
}
2009-11-19 17:04:21 -05:00
virtual void visit ( AstValuePlusArgs * nodep , AstNUser * ) {
string prefix ;
char format = '?' ;
bool pct = false ;
int got = 0 ;
for ( const char * cp = nodep -> text (). c_str (); * cp ; cp ++ ) {
if ( pct ) {
pct = false ;
switch ( tolower ( * cp )) {
case '%' :
prefix += * cp ;
break ;
case 'd' : // FALLTHRU
case 'o' : // FALLTHRU
case 'h' : // FALLTHRU
case 'x' : // FALLTHRU
case 'b' : // FALLTHRU
case 's' :
got ++ ; format = tolower ( * cp );
break ;
case 'e' : // FALLTHRU
case 'f' : // FALLTHRU
case 'g' :
got ++ ; format = tolower ( * cp );
nodep -> v3error ( "Unsupported $value$plusargs format qualifier: '" <<* cp << "'" << endl );
break ;
default :
got ++ ;
nodep -> v3error ( "Illegal $value$plusargs format qualifier: '" <<* cp << "'" << endl );
break ;
}
}
else if ( * cp == '%' ) pct = true ;
else prefix += * cp ;
}
if ( got != 1 ) nodep -> v3error ( "Missing or extra $value$plusargs format qualifier: '" << nodep -> text () << "'" << endl );
puts ( "VL_VALUEPLUSARGS_I" );
emitIQW ( nodep -> exprsp ());
puts ( "(" );
puts ( cvtToStr ( nodep -> exprsp () -> widthMin ())); // Note argument width, not node width (which is always 32)
putbs ( "," );
putsQuoted ( prefix );
2009-11-23 21:24:55 -05:00
putbs ( "," );
puts ( "'" ); puts ( cvtToStr ( format )); puts ( "'" );
puts ( "," );
2009-11-19 17:04:21 -05:00
nodep -> exprsp () -> iterateAndNext ( * this );
puts ( ")" );
}
virtual void visit ( AstTestPlusArgs * nodep , AstNUser * ) {
puts ( "VL_TESTPLUSARGS_I(" );
putsQuoted ( nodep -> text ());
puts ( ")" );
}
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 ) {
2010-01-15 20:07:16 -05:00
nodep -> v3error ( "String of " << nodep -> width () << " bits exceeds hardcoded limit VL_TO_STRING_MAX_WORDS in verilatedos.h" );
2008-07-01 14:15:10 -04:00
}
}
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 ();
2009-11-04 22:31:53 -05:00
if ( ! varrefp ) { nodep -> v3error ( "Readmem loading non-variable" ); }
2009-11-06 23:16:06 -05:00
else if ( AstArrayDType * adtypep = varrefp -> varp () -> dtypeSkipRefp () -> castArrayDType ()) {
2012-02-28 21:33:17 -05:00
puts ( cvtToStr ( varrefp -> varp () -> dtypep () -> arrayElements ()));
2009-11-04 22:31:53 -05:00
array_lsb = adtypep -> lsb ();
}
else {
nodep -> v3error ( "Readmem loading non-arrayed variable" );
2006-12-19 14:09:57 +00:00
}
}
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 * ) {
2011-07-01 13:41:21 -04:00
puts ( "VL_FCLOSE_I(" );
2006-08-26 11:35:28 +00:00
nodep -> filep () -> iterateAndNext ( * this );
2011-07-01 13:41:21 -04:00
puts ( "); " );
2006-08-26 11:35:28 +00:00
nodep -> filep () -> iterateAndNext ( * this ); // For saftey, so user doesn't later WRITE with it.
2011-07-01 13:41:21 -04:00
puts ( "=0; \n " );
2006-08-26 11:35:28 +00:00
}
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 );
2011-07-01 13:41:21 -04:00
puts ( ") { fflush (VL_CVT_I_FP(" );
2008-07-16 14:06:08 -04:00
nodep -> filep () -> iterateAndNext ( * this );
puts ( ")); } \n " );
}
2008-06-27 08:45:05 -04:00
}
2011-11-20 02:01:48 -05:00
virtual void visit ( AstSystemT * nodep , AstNUser * ) {
puts ( "(void)VL_SYSTEM_I" );
emitIQW ( nodep -> lhsp ());
puts ( "(" );
if ( nodep -> lhsp () -> isWide ()) {
puts ( cvtToStr ( nodep -> lhsp () -> widthWords ()));
putbs ( ", " );
}
checkMaxWords ( nodep -> lhsp ());
nodep -> lhsp () -> iterateAndNext ( * this );
puts ( "); \n " );
}
virtual void visit ( AstSystemF * nodep , AstNUser * ) {
puts ( "VL_SYSTEM_I" );
emitIQW ( nodep -> lhsp ());
puts ( "(" );
if ( nodep -> lhsp () -> isWide ()) {
puts ( cvtToStr ( nodep -> lhsp () -> widthWords ()));
putbs ( ", " );
}
checkMaxWords ( nodep -> lhsp ());
nodep -> lhsp () -> iterateAndNext ( * this );
puts ( ")" );
}
2010-02-14 10:01:21 -05:00
virtual void visit ( AstJumpGo * nodep , AstNUser * ) {
puts ( "goto __Vlabel" + cvtToStr ( nodep -> labelp () -> labelNum ()) + "; \n " );
}
virtual void visit ( AstJumpLabel * nodep , AstNUser * ) {
puts ( "{ \n " );
nodep -> stmtsp () -> iterateAndNext ( * this );
puts ( "} \n " );
puts ( "__Vlabel" + cvtToStr ( nodep -> labelNum ()) + ": ; \n " );
}
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 );
2010-02-14 10:01:21 -05:00
nodep -> incsp () -> iterateAndNext ( * this );
2006-08-26 11:35:28 +00:00
nodep -> precondsp () -> iterateAndNext ( * this ); // Need to recompute before next loop
puts ( "} \n " );
}
virtual void visit ( AstNodeIf * nodep , AstNUser * ) {
puts ( "if (" );
2010-02-01 20:15:48 -05:00
if ( nodep -> branchPred () != AstBranchPred :: BP_UNKNOWN ) {
2006-08-26 11:35:28 +00:00
puts ( nodep -> branchPred (). ascii ()); puts ( "(" );
}
nodep -> condp () -> iterateAndNext ( * this );
2010-02-01 20:15:48 -05:00
if ( nodep -> branchPred () != AstBranchPred :: BP_UNKNOWN ) puts ( ")" );
2006-08-26 11:35:28 +00:00
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 * ) {
2009-12-02 19:32:41 -05:00
if ( nodep -> tracking ()) {
puts ( nodep -> text ());
} else {
ofp () -> putsNoTracking ( nodep -> text ());
}
2006-08-26 11:35:28 +00:00
}
virtual void visit ( AstCStmt * nodep , AstNUser * ) {
2009-12-01 21:55:56 -05:00
putbs ( "" );
2006-08-26 11:35:28 +00:00
nodep -> bodysp () -> iterateAndNext ( * this );
}
virtual void visit ( AstCMath * nodep , AstNUser * ) {
2009-12-01 21:55:56 -05:00
putbs ( "" );
2006-08-26 11:35:28 +00:00
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_" );
2012-04-29 11:34:25 -04:00
puts ( cvtToStr ( nodep -> lhsp () -> dtypep () -> widthPow2 ()));
2006-08-26 11:35:28 +00:00
puts ( "(" );
nodep -> lhsp () -> iterateAndNext ( * this );
puts ( ")" );
}
}
virtual void visit ( AstMulS * nodep , AstNUser * vup ) {
if ( nodep -> widthWords () > VL_MULS_MAX_WORDS ) {
2010-01-15 20:07:16 -05:00
nodep -> v3error ( "Unsupported: Signed multiply of " << nodep -> width () << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h" );
2006-08-26 11:35:28 +00:00
}
visit ( nodep -> castNodeBiop (), vup );
}
2011-03-17 21:09:52 -04:00
virtual void visit ( AstCCast * nodep , AstNUser * ) {
2006-08-26 11:35:28 +00:00
// 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_" );
2011-11-30 18:50:21 -05:00
puts ( cvtToStr ( VL_WORDS_I ( nodep -> num (). widthMin ())));
2006-08-26 11:35:28 +00:00
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 );
}
2011-11-30 18:50:21 -05:00
for ( int word = VL_WORDS_I ( nodep -> num (). widthMin ()) - 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
2010-04-09 21:51:15 -04:00
ofp () -> printf ( ",0x%08" VL_PRI64 "x" , ( vluint64_t )( nodep -> num (). dataWord ( word )));
2006-08-26 11:35:28 +00:00
}
2010-04-09 21:51:15 -04:00
ofp () -> printf ( ",0x%08" VL_PRI64 "x)" , ( vluint64_t )( nodep -> num (). dataWord ( 0 )));
2011-07-24 15:01:51 -04:00
} else if ( nodep -> isDouble ()) {
2011-09-28 21:35:16 -04:00
ofp () -> printf ( "%.17g" , nodep -> num (). toDouble ());
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 ();
2010-04-09 21:51:15 -04:00
if ( num < 10 ) ofp () -> printf ( "VL_ULL(%" VL_PRI64 "d)" , num );
else ofp () -> printf ( "VL_ULL(0x%" VL_PRI64 "x)" , num );
2006-08-26 11:35:28 +00:00
} else {
2008-09-04 11:03:46 -04:00
uint32_t num = nodep -> toUInt ();
2010-04-09 21:51:15 -04:00
// Only 32 bits - llx + long long here just to appease CPP format warning
2006-08-26 11:35:28 +00:00
if ( num < 10 ) puts ( cvtToStr ( num ));
2010-04-09 21:51:15 -04:00
else ofp () -> printf ( "0x%" VL_PRI64 "x" , ( vluint64_t ) 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 , "" );
}
}
2010-01-17 20:06:08 -05:00
virtual void visit ( AstConstString * nodep , AstNUser * ) {
putsQuoted ( nodep -> name ());
}
2006-08-26 11:35:28 +00:00
// Just iterate
2009-12-01 21:55:56 -05:00
virtual void visit ( AstNetlist * nodep , AstNUser * ) {
nodep -> iterateChildren ( * this );
}
2006-08-26 11:35:28 +00:00
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
2009-12-01 21:55:56 -05:00
virtual void visit ( AstCFile * , AstNUser * ) {} // Handled outside the Visit class
2012-07-29 10:16:20 -04:00
virtual void visit ( AstTypedef * , AstNUser * ) {} // Nothing needed presently
2006-08-26 11:35:28 +00:00
// Default
virtual void visit ( AstNode * nodep , AstNUser * ) {
2009-07-09 17:39:24 -04:00
puts (( string ) " \n ???? // " + nodep -> prettyTypeName () + " \n " );
2006-08-26 11:35:28 +00:00
nodep -> iterateChildren ( * this );
2009-07-09 17:39:24 -04:00
nodep -> v3fatalSrc ( "Unknown node type reached emitter: " << nodep -> prettyTypeName ());
2006-08-26 11:35:28 +00:00
}
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
2009-11-07 06:20:20 -05:00
AstNodeModule * m_modp ;
2006-08-26 11:35:28 +00:00
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 {
2012-04-09 20:17:51 -04:00
AstNode * lhsp = changep -> lhsp ();
AstNode * rhsp = changep -> rhsp ();
if ( ! lhsp -> castVarRef () && ! lhsp -> castArraySel ()) changep -> v3fatalSrc ( "Not ref?" );
if ( ! rhsp -> castVarRef () && ! rhsp -> castArraySel ()) changep -> v3fatalSrc ( "Not ref?" );
2006-08-26 11:35:28 +00:00
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 );
2012-02-20 20:48:13 -05:00
if ( changep -> lhsp () -> isWide ()) puts ( "[" + cvtToStr ( word ) + "]" );
2006-08-26 11:35:28 +00:00
puts ( " ^ " );
changep -> rhsp () -> iterateAndNext ( * this );
2012-02-20 20:48:13 -05:00
if ( changep -> lhsp () -> isWide ()) puts ( "[" + cvtToStr ( word ) + "]" );
2006-08-26 11:35:28 +00:00
puts ( ")" );
}
}
}
2009-11-07 06:20:20 -05:00
V3OutCFile * newOutCFile ( AstNodeModule * modp , bool slow , bool source , int filenum = 0 ) {
2006-08-26 11:35:28 +00:00
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 );
}
2009-12-02 21:15:56 -05:00
2006-08-26 11:35:28 +00:00
ofp -> putsHeader ();
2009-12-02 21:15:56 -05:00
if ( modp -> isTop () && ! source ) {
ofp -> puts ( "// DESCR" "IPTION: Verilator output: Primary design header \n " );
ofp -> puts ( "// \n " );
ofp -> puts ( "// This header should be included by all source files instantiating the design. \n " );
ofp -> puts ( "// The class here is then constructed to instantiate the design. \n " );
ofp -> puts ( "// See the Verilator manual for examples. \n " );
} else {
if ( source ) {
ofp -> puts ( "// DESCR" "IPTION: Verilator output: Design implementation internals \n " );
} else {
ofp -> puts ( "// DESCR" "IPTION: Verilator output: Design internal header \n " );
}
ofp -> puts ( "// See " + v3Global . opt . prefix () + ".h for the primary calling header \n " );
}
ofp -> puts ( " \n " );
2006-08-26 11:35:28 +00:00
return ofp ;
}
//---------------------------------------
// VISITORS
virtual void visit ( AstCFunc * nodep , AstNUser * ) {
2009-12-03 06:55:29 -05:00
// TRACE_* and DPI handled elsewhere
if ( nodep -> funcType (). isTrace ()) return ;
if ( nodep -> dpiImport ()) return ;
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 " );
2010-01-14 21:03:06 -05:00
puts ( "VL_DEBUG_IF(VL_PRINTF( \" " );
2006-08-26 11:35:28 +00:00
for ( int i = 0 ; i < m_modp -> level (); i ++ ) { puts ( " " ); }
puts ( modClassName ( m_modp ) + "::" + nodep -> name ()
2010-01-14 21:03:06 -05:00
+ " \\ n \" ); ); \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 ();
}
2010-01-14 21:03:06 -05:00
puts ( ")) VL_PRINTF( \"\t CHANGE: " + nodep -> fileline () -> ascii ()
+ varname + " \\ n \" ); ); \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
2009-11-07 06:20:20 -05:00
void emitVarResets ( AstNodeModule * modp );
void emitCellCtors ( AstNodeModule * modp );
2006-08-26 11:35:28 +00:00
void emitSensitives ();
// Medium level
2009-11-07 06:20:20 -05:00
void emitCtorImp ( AstNodeModule * modp );
void emitConfigureImp ( AstNodeModule * modp );
void emitCoverageDecl ( AstNodeModule * modp );
void emitCoverageImp ( AstNodeModule * modp );
void emitDestructorImp ( AstNodeModule * modp );
2006-08-26 11:35:28 +00:00
void emitTextSection ( AstType type );
2009-11-07 06:20:20 -05:00
void emitIntFuncDecls ( AstNodeModule * modp );
2006-08-26 11:35:28 +00:00
// High level
2009-11-07 06:20:20 -05:00
void emitImp ( AstNodeModule * modp );
void emitStaticDecl ( AstNodeModule * modp );
void emitWrapEval ( AstNodeModule * modp );
void emitInt ( AstNodeModule * modp );
2006-08-26 11:35:28 +00:00
void writeMakefile ( string filename );
public :
EmitCImp () {
m_modp = NULL ;
2011-08-04 21:58:45 -04:00
m_slow = false ;
m_fast = false ;
2006-08-26 11:35:28 +00:00
}
virtual ~ EmitCImp () {}
2009-11-07 06:20:20 -05:00
void main ( AstNodeModule * modp , bool slow , bool fast );
2006-08-26 11:35:28 +00:00
void mainDoFunc ( AstCFunc * nodep ) {
nodep -> accept ( * this );
}
};
//######################################################################
// Internal EmitCStmts
void EmitCStmts :: emitVarDecl ( AstVar * nodep , const string & prefixIfImp ) {
2009-11-15 08:52:19 -05:00
AstBasicDType * basicp = nodep -> basicp (); if ( ! basicp ) nodep -> v3fatalSrc ( "Unimplemented: Outputting this data type" );
2006-08-26 11:35:28 +00:00
if ( nodep -> isIO ()) {
2010-01-19 13:18:40 -05:00
bool isArray = ! nodep -> dtypeSkipRefp () -> castBasicDType ();
2006-08-26 11:35:28 +00:00
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 ());
2012-02-01 20:20:43 -05:00
if ( isArray ) {
2012-03-03 12:10:29 -05:00
for ( AstArrayDType * arrayp = nodep -> dtypeSkipRefp () -> castArrayDType (); arrayp ;
2012-04-14 12:43:03 -04:00
arrayp = arrayp -> subDTypep () -> skipRefp () -> castArrayDType ()) {
2012-02-01 20:20:43 -05:00
puts ( "[" + cvtToStr ( arrayp -> elementsConst ()) + "]" );
}
}
2006-08-26 11:35:28 +00:00
puts ( "; \n " );
} else { // C++ signals
2009-11-06 23:16:06 -05:00
ofp () -> putAlign ( nodep -> isStatic (), nodep -> dtypeSkipRefp () -> widthAlignBytes (),
nodep -> dtypeSkipRefp () -> widthTotalBytes ());
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" );
2010-01-19 13:18:40 -05:00
if ( isArray ) {
if ( nodep -> isWide ()) puts ( "W" );
puts ( "(" + nodep -> name ());
2012-03-03 12:10:29 -05:00
for ( AstArrayDType * arrayp = nodep -> dtypeSkipRefp () -> castArrayDType (); arrayp ;
2012-04-14 12:43:03 -04:00
arrayp = arrayp -> subDTypep () -> skipRefp () -> castArrayDType ()) {
2010-01-19 13:18:40 -05:00
puts ( "[" + cvtToStr ( arrayp -> elementsConst ()) + "]" );
}
puts ( "," + cvtToStr ( basicp -> msb ()) + "," + cvtToStr ( basicp -> lsb ()));
if ( basicp -> isWide ()) puts ( "," + cvtToStr ( basicp -> widthWords ()));
} else {
if ( ! basicp -> isWide ())
puts ( "(" + nodep -> name ()
+ "," + cvtToStr ( basicp -> msb ())
+ "," + cvtToStr ( basicp -> lsb ()));
else puts ( "W(" + nodep -> name ()
+ "," + cvtToStr ( basicp -> msb ())
+ "," + cvtToStr ( basicp -> lsb ())
+ "," + cvtToStr ( basicp -> widthWords ()));
}
2006-08-26 11:35:28 +00:00
puts ( "); \n " );
}
2010-01-17 15:10:37 -05:00
} else if ( basicp && basicp -> isOpaque ()) {
// strings and other fundamental c types
puts ( nodep -> vlArgType ( true , false ));
// This isn't very robust and may need cleanup for other data types
2012-03-03 12:10:29 -05:00
for ( AstArrayDType * arrayp = nodep -> dtypeSkipRefp () -> castArrayDType (); arrayp ;
2012-04-14 12:43:03 -04:00
arrayp = arrayp -> subDTypep () -> skipRefp () -> castArrayDType ()) {
2010-01-17 15:10:37 -05:00
puts ( "[" + cvtToStr ( arrayp -> elementsConst ()) + "]" );
}
puts ( "; \n " );
2006-08-26 11:35:28 +00:00
} else {
// Arrays need a small alignment, but may need different padding after.
// For example three VL_SIG8's needs alignment 1 but size 3.
2009-11-06 23:16:06 -05:00
ofp () -> putAlign ( nodep -> isStatic (), nodep -> dtypeSkipRefp () -> widthAlignBytes (),
nodep -> dtypeSkipRefp () -> widthTotalBytes ());
2006-08-29 00:58:48 +00:00
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 ());
2009-11-04 22:31:53 -05:00
// This isn't very robust and may need cleanup for other data types
2012-03-03 12:10:29 -05:00
for ( AstArrayDType * arrayp = nodep -> dtypeSkipRefp () -> castArrayDType (); arrayp ;
2012-04-14 12:43:03 -04:00
arrayp = arrayp -> subDTypep () -> skipRefp () -> castArrayDType ()) {
2006-08-26 11:35:28 +00:00
puts ( "[" + cvtToStr ( arrayp -> elementsConst ()) + "]" );
}
2009-11-15 08:52:19 -05:00
puts ( "," + cvtToStr ( basicp -> msb ()) + "," + cvtToStr ( basicp -> lsb ()));
if ( basicp -> isWide ()) puts ( "," + cvtToStr ( basicp -> widthWords ()));
2006-08-26 11:35:28 +00:00
puts ( "); \n " );
}
}
void EmitCStmts :: emitVarCtors () {
2012-02-01 20:20:43 -05:00
if ( ! m_ctorVarsVec . empty ()) {
ofp () -> indentInc ();
puts ( " \n " );
puts ( "#if (SYSTEMC_VERSION>20011000) \n " ); // SystemC 2.0.1 and newer
bool first = true ;
for ( vector < AstVar *>:: iterator it = m_ctorVarsVec . begin (); it != m_ctorVarsVec . end (); ++ it ) {
AstVar * varp = * it ;
bool isArray = ! varp -> dtypeSkipRefp () -> castBasicDType ();
if ( isArray ) {
puts ( "// Skipping array: " );
puts ( varp -> name ());
puts ( " \n " );
} else {
if ( first ) { puts ( " : " ); first = false ; }
else puts ( ", " );
if ( ofp () -> exceededWidth ()) puts ( " \n " );
puts ( varp -> name ());
puts ( "(" ); putsQuoted ( varp -> name ()); puts ( ")" );
}
2006-08-26 11:35:28 +00:00
}
2012-02-01 20:20:43 -05:00
puts ( " \n #endif \n " );
ofp () -> indentDec ();
2006-08-26 11:35:28 +00:00
}
}
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 ;
2012-03-20 16:01:53 -04:00
case 'w' :
2008-06-29 20:02:24 -04:00
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
2010-01-19 10:29:13 -05:00
bool isStmt = false ;
2008-07-01 14:15:10 -04:00
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(" );
}
2009-11-23 21:24:55 -05:00
} else if ( AstSFormat * dispp = nodep -> castSFormat ()) {
isStmt = true ;
puts ( "VL_SFORMAT_X(" );
puts ( cvtToStr ( dispp -> lhsp () -> widthMin ()));
putbs ( "," );
dispp -> lhsp () -> iterate ( * this );
putbs ( "," );
2010-01-17 19:13:44 -05:00
} else if ( AstSFormatF * dispp = nodep -> castSFormatF ()) {
2010-01-19 10:29:13 -05:00
isStmt = false ;
2010-01-17 19:13:44 -05:00
if ( dispp ) {}
puts ( "VL_SFORMATF_NX(" );
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
}
2009-10-22 21:16:52 -04:00
ofp () -> putsQuoted ( emitDispState . m_format );
2006-08-26 11:35:28 +00:00
// 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
2012-05-02 21:04:50 -04:00
dispp -> v3error ( "Internal: Missing arguments for $display-like 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 ) {
2012-05-02 21:04:50 -04:00
dispp -> v3error ( "Exceeded limit of " + cvtToStr ( VL_VALUE_STRING_MAX_WIDTH ) + " bits for any $display-like arguments" );
2006-08-26 11:35:28 +00:00
}
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 ();
}
2010-01-17 15:53:12 -05:00
void EmitCStmts :: displayNode ( AstNode * nodep , AstScopeName * scopenamep ,
const string & vformat , AstNode * exprsp ,
2008-07-01 14:15:10 -04:00
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' :
2011-07-23 19:58:34 -04:00
case '.' :
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 ;
2011-07-23 19:58:34 -04:00
case 'e' : displayArg ( nodep , & elistp , isScan , vfmt , 'e' ); break ;
case 'f' : displayArg ( nodep , & elistp , isScan , vfmt , 'f' ); break ;
case 'g' : displayArg ( nodep , & elistp , isScan , vfmt , 'g' ); break ;
2008-06-30 14:31:58 -04:00
case 'm' : {
2008-07-01 14:15:10 -04:00
if ( ! scopenamep ) nodep -> v3fatalSrc ( "Display with %m but no AstScopeName" );
2010-02-03 19:19:18 -05:00
string suffix = scopenamep -> scopePrettyName ();
if ( suffix == "" ) emitDispState . pushFormat ( "%S" );
else emitDispState . pushFormat ( "%N" ); // Add a . when needed
emitDispState . pushArg ( NULL , "vlSymsp->name()" );
emitDispState . pushFormat ( suffix );
2008-06-30 14:31:58 -04:00
break ;
}
case 'u' :
case 'z' :
case 'l' :
case 'v' :
2012-05-02 21:04:50 -04:00
nodep -> v3error ( "Unsupported: $display-like format code: %" << pos [ 0 ]);
2008-06-30 14:31:58 -04:00
break ;
default :
2012-05-02 21:04:50 -04:00
nodep -> v3error ( "Unknown $display-like format code: %" << pos [ 0 ]);
2008-06-30 14:31:58 -04:00
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
2012-05-02 21:04:50 -04:00
elistp -> v3error ( "Internal: Extra arguments for $display-like format" );
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
2009-11-07 06:20:20 -05:00
void EmitCImp :: emitVarResets ( AstNodeModule * modp ) {
2006-08-26 11:35:28 +00:00
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.
}
2010-01-17 15:10:37 -05:00
else if ( varp -> basicp () && varp -> basicp () -> keyword () == AstBasicDTypeKwd :: STRING ) {
// Constructor deals with it
}
2006-08-26 11:35:28 +00:00
else if ( varp -> isParam ()) {
if ( ! varp -> hasSimpleInit ()) nodep -> v3fatalSrc ( "No init for a param?" );
2010-01-21 18:20:47 -05:00
//puts("// parameter "+varp->name()+" = "+varp->valuep()->name()+"\n");
2006-08-26 11:35:28 +00:00
}
2010-01-21 18:20:47 -05:00
else if ( AstInitArray * initarp = varp -> valuep () -> castInitArray ()) {
2006-08-26 11:35:28 +00:00
AstConst * constsp = initarp -> initsp () -> castConst ();
2009-11-06 23:16:06 -05:00
if ( AstArrayDType * arrayp = varp -> dtypeSkipRefp () -> castArrayDType ()) {
2009-11-04 22:31:53 -05:00
for ( int i = 0 ; i < arrayp -> elementsConst (); i ++ ) {
if ( ! constsp ) initarp -> v3fatalSrc ( "Not enough values in array initalizement" );
emitSetVarConstant ( varp -> name () + "[" + cvtToStr ( i ) + "]" , constsp );
constsp = constsp -> nextp () -> castConst ();
}
} else {
varp -> v3fatalSrc ( "InitArray under non-arrayed var" );
2006-08-26 11:35:28 +00:00
}
}
else {
int vects = 0 ;
2009-11-04 22:31:53 -05:00
// This isn't very robust and may need cleanup for other data types
2009-11-06 23:16:06 -05:00
for ( AstArrayDType * arrayp = varp -> dtypeSkipRefp () -> castArrayDType (); arrayp ;
2012-04-14 12:43:03 -04:00
arrayp = arrayp -> subDTypep () -> skipRefp () -> castArrayDType ()) {
2006-08-26 11:35:28 +00:00
int vecnum = vects ++ ;
2009-11-04 22:31:53 -05:00
if ( arrayp -> msb () < arrayp -> lsb ()) varp -> v3fatalSrc ( "Should have swapped msb & lsb earlier." );
2006-08-26 11:35:28 +00:00
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
2009-11-23 19:08:25 -05:00
|| ( varp -> basicp () && varp -> basicp () -> isZeroInit ())
2006-08-26 11:35:28 +00:00
|| ( 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 ) {
2012-01-26 08:29:55 -05:00
puts ( " = 0; \n " );
2006-08-26 11:35:28 +00:00
} else {
puts ( " = VL_RAND_RESET_" );
emitIQW ( varp );
puts ( "(" );
puts ( cvtToStr ( varp -> widthMin ()));
puts ( "); \n " );
}
}
for ( int v = 0 ; v < vects ; ++ v ) puts ( "}} \n " );
}
}
}
}
2009-11-07 06:20:20 -05:00
void EmitCImp :: emitCoverageDecl ( AstNodeModule * 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
}
}
2009-11-07 06:20:20 -05:00
void EmitCImp :: emitCtorImp ( AstNodeModule * modp ) {
2006-08-30 17:27:53 +00:00
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 );
2010-01-21 18:04:36 -05:00
emitTextSection ( AstType :: atSCCTOR );
2006-08-30 17:27:53 +00:00
if ( optSystemPerl ()) puts ( "SP_AUTO_CTOR; \n " );
puts ( "} \n " );
}
2009-11-07 06:20:20 -05:00
void EmitCImp :: emitConfigureImp ( AstNodeModule * 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 " );
}
2009-11-07 06:20:20 -05:00
void EmitCImp :: emitCoverageImp ( AstNodeModule * 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 " );
}
}
2009-11-07 06:20:20 -05:00
void EmitCImp :: emitDestructorImp ( AstNodeModule * modp ) {
2006-08-30 17:27:53 +00:00
puts ( " \n " );
puts ( modClassName ( modp ) + "::~" + modClassName ( modp ) + "() { \n " );
2010-01-21 18:04:36 -05:00
emitTextSection ( AstType :: atSCDTOR );
2006-08-30 17:27:53 +00:00
if ( modp -> isTop ()) puts ( "delete __VlSymsp; __VlSymsp=NULL; \n " );
puts ( "} \n " );
}
2009-11-07 06:20:20 -05:00
void EmitCImp :: emitStaticDecl ( AstNodeModule * modp ) {
2006-08-26 11:35:28 +00:00
// 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());
2011-08-04 21:58:45 -04:00
puts ( "" ); // NOP for cppcheck, otherwise const function
2006-08-26 11:35:28 +00:00
}
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 " );
}
}
2009-11-07 06:20:20 -05:00
void EmitCImp :: emitCellCtors ( AstNodeModule * modp ) {
2006-08-26 11:35:28 +00:00
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 ())) {
2012-02-01 20:20:43 -05:00
int vects = 0 ;
// This isn't very robust and may need cleanup for other data types
for ( AstArrayDType * arrayp = varp -> dtypeSkipRefp () -> castArrayDType (); arrayp ;
2012-04-14 12:43:03 -04:00
arrayp = arrayp -> subDTypep () -> skipRefp () -> castArrayDType ()) {
2012-02-01 20:20:43 -05:00
int vecnum = vects ++ ;
if ( arrayp -> msb () < arrayp -> lsb ()) 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 ( arrayp -> lsb ()) + ";" );
puts ( " for (; " + ivar + "<=" + cvtToStr ( arrayp -> msb ()));
puts ( "; ++" + ivar + ") { \n " );
}
puts ( "sensitive << " + varp -> name ());
for ( int v = 0 ; v < vects ; ++ v ) puts ( "[__Vi" + cvtToStr ( v ) + "]" );
puts ( "; \n " );
for ( int v = 0 ; v < vects ; ++ v ) puts ( "}} \n " );
2006-08-26 11:35:28 +00:00
}
}
}
puts ( " \n " );
}
}
2009-11-07 06:20:20 -05:00
void EmitCImp :: emitWrapEval ( AstNodeModule * modp ) {
2006-08-26 11:35:28 +00:00
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 " );
2010-01-14 21:03:06 -05:00
puts ( "VL_DEBUG_IF(VL_PRINTF( \"\\ n----TOP Evaluate " + modClassName ( modp ) + "::eval \\ n \" ); ); \n " );
2006-08-26 11:35:28 +00:00
#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 " );
2010-01-14 21:03:06 -05:00
puts ( "VL_DEBUG_IF(VL_PRINTF( \" Clock loop \\ n \" );); \n " );
2006-08-26 11:35:28 +00:00
#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 " );
2012-05-31 18:56:31 -04:00
puts ( "if (++__VclockLoop > " + cvtToStr ( v3Global . opt . convergeLimit ())
+ ") vl_fatal(__FILE__,__LINE__,__FILE__, \" Verilated model didn't converge \" ); \n " );
2006-08-26 11:35:28 +00:00
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 " );
2012-05-31 18:56:31 -04:00
puts ( "if (++__VclockLoop > " + cvtToStr ( v3Global . opt . convergeLimit ())
+ ") vl_fatal(__FILE__,__LINE__,__FILE__, \" Verilated model didn't DC converge \" ); \n " );
2006-08-26 11:35:28 +00:00
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 ;
2010-01-17 15:10:37 -05:00
const int sortmax = 9 ;
for ( int sort = 0 ; sort < sortmax ; sort ++ ) {
if ( sort == 3 ) continue ;
2006-08-29 00:58:48 +00:00
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 ) {
2009-11-06 23:16:06 -05:00
int sigbytes = varp -> dtypeSkipRefp () -> widthAlignBytes ();
2010-01-17 15:10:37 -05:00
int sortbytes = sortmax - 1 ;
2009-11-04 22:31:53 -05:00
if ( varp -> isUsedClock () && varp -> widthMin () == 1 ) sortbytes = 0 ;
2010-01-17 15:10:37 -05:00
else if ( varp -> dtypeSkipRefp () -> castArrayDType ()) sortbytes = 8 ;
else if ( varp -> basicp () && varp -> basicp () -> isOpaque ()) sortbytes = 7 ;
2009-11-04 22:31:53 -05:00
else if ( varp -> isScBv ()) sortbytes = 6 ;
else if ( sigbytes == 8 ) sortbytes = 5 ;
else if ( sigbytes == 4 ) sortbytes = 4 ;
else if ( sigbytes == 2 ) sortbytes = 2 ;
else if ( sigbytes == 1 ) sortbytes = 1 ;
2010-01-17 15:10:37 -05:00
if ( sort == sortbytes ) {
2006-08-29 00:58:48 +00:00
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 ();
}
};
2009-11-07 06:20:20 -05:00
void EmitCImp :: emitIntFuncDecls ( AstNodeModule * modp ) {
2006-08-26 11:35:28 +00:00
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 ;
2009-12-03 06:55:29 -05:00
if ( ! funcp -> dpiImport ()) { // DPI is prototyped in __Dpi.h
ofp () -> putsPrivate ( funcp -> declPrivate ());
if ( funcp -> isStatic ()) puts ( "static " );
puts ( funcp -> rtnTypeVoid ()); puts ( " \t " );
puts ( funcp -> name ()); puts ( "(" + cFuncArgs ( funcp ) + "); \n " );
}
2006-08-26 11:35:28 +00:00
}
}
2009-11-07 06:20:20 -05:00
void EmitCImp :: emitInt ( AstNodeModule * modp ) {
2006-08-26 11:35:28 +00:00
// 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 ();
2010-01-17 15:10:37 -05:00
if ( v3Global . needHeavy ()) {
2010-01-24 08:38:17 -05:00
puts ( "#include \" verilated_heavy.h \"\n " );
2010-01-17 15:10:37 -05:00
} else {
puts ( "#include \" verilated.h \"\n " );
}
2006-08-26 11:35:28 +00:00
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
}
2011-05-12 06:59:13 -04:00
if ( v3Global . dpi ()) {
// do this before including our main .h file so that any references to
// types defined in svdpi.h are available
puts ( "#include \" " + topClassName () + "__Dpi.h \"\n " );
puts ( " \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 ()) {
2010-01-24 18:37:01 -05:00
puts ( "class " + v3Global . opt . traceClassBase () + "; \n " );
2008-01-15 18:36:47 +00:00
}
2006-08-26 11:35:28 +00:00
puts ( " \n //---------- \n\n " );
2010-01-21 18:04:36 -05:00
emitTextSection ( AstType :: atSCHDR );
2006-08-26 11:35:28 +00:00
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 " );
2009-12-02 21:15:56 -05:00
if ( modp -> isTop ()) puts ( "// Public to allow access to /*verilator_public*/ items; \n " );
if ( modp -> isTop ()) puts ( "// otherwise the application code can consider these internals. \n " );
2006-08-26 11:35:28 +00:00
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 " );
2009-12-02 21:15:56 -05:00
if ( modp -> isTop ()) puts ( "// The application code writes and reads these signals to \n " );
if ( modp -> isTop ()) puts ( "// propagate new values into/out from the Verilated model. \n " );
2006-08-26 11:35:28 +00:00
emitVarList ( modp -> stmtsp (), EVL_IO , "" );
puts ( " \n // LOCAL SIGNALS \n " );
2009-12-02 21:15:56 -05:00
if ( modp -> isTop ()) puts ( "// Internals; generally not touched by application code \n " );
2006-08-26 11:35:28 +00:00
emitVarList ( modp -> stmtsp (), EVL_SIG , "" );
puts ( " \n // LOCAL VARIABLES \n " );
2009-12-02 21:15:56 -05:00
if ( modp -> isTop ()) puts ( "// Internals; generally not touched by application code \n " );
2006-08-26 11:35:28 +00:00
emitVarList ( modp -> stmtsp (), EVL_TEMP , "" );
puts ( " \n // INTERNAL VARIABLES \n " );
2009-12-02 21:15:56 -05:00
if ( modp -> isTop ()) puts ( "// Internals; generally not touched by application code \n " );
2006-08-26 11:35:28 +00:00
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 " );
2009-12-02 21:15:56 -05:00
if ( modp -> isTop ()) puts ( "// Parameters marked /*verilator public*/ for use by application code \n " );
2006-08-26 11:35:28 +00:00
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 ())) {
2010-01-21 18:20:47 -05:00
if ( ! varp -> valuep ()) nodep -> v3fatalSrc ( "No init for a param?" );
2006-08-26 11:35:28 +00:00
// 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" );
2010-01-21 18:20:47 -05:00
} else if ( ! varp -> valuep () -> castConst ()) { // Unsupported for output
2006-08-26 11:35:28 +00:00
puts ( "// enum IData " + varp -> name () + " //not simple value" );
} else {
puts ( "enum " );
puts ( varp -> isQuad () ? "_QData" : "_IData" );
puts ( "" + varp -> name () + " { " + varp -> name () + " = " );
2010-01-21 18:20:47 -05:00
varp -> valuep () -> iterateAndNext ( * this );
2006-08-26 11:35:28 +00:00
puts ( "};" );
}
puts ( " \n " );
}
}
}
2009-12-02 21:15:56 -05:00
puts ( " \n // CONSTRUCTORS \n " );
2006-08-26 11:35:28 +00:00
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 {
2010-02-02 21:09:11 -05:00
if ( modp -> isTop ()) {
puts ( "/// Construct the model; called by application code \n " );
puts ( "/// The special name "" may be used to make a wrapper with a \n " );
puts ( "/// single model invisible WRT DPI scope names. \n " );
}
2006-08-26 11:35:28 +00:00
puts ( modClassName ( modp ) + "(const char* name= \" TOP \" ); \n " );
2009-12-02 21:15:56 -05:00
if ( modp -> isTop ()) puts ( "/// Destroy the model; called (often implicitly) by application code \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 ()) {
2009-12-02 21:15:56 -05:00
if ( modp -> isTop ()) puts ( "/// Trace signals in the model; called by application code \n " );
2010-01-24 18:37:01 -05:00
puts ( "void trace (VerilatedVcdC* tfp, int levels, int options=0); \n " );
2006-08-26 11:35:28 +00:00
}
2009-12-02 21:15:56 -05:00
puts ( " \n // USER METHODS \n " );
if ( optSystemPerl ()) puts ( "/*AUTOMETHODS*/ \n " );
2010-01-21 18:04:36 -05:00
emitTextSection ( AstType :: atSCINT );
2006-08-26 11:35:28 +00:00
2009-12-02 21:15:56 -05:00
puts ( " \n // API METHODS \n " );
2006-08-26 11:35:28 +00:00
if ( modp -> isTop ()) {
if ( optSystemC ()) ofp () -> putsPrivate ( true ); ///< eval() is invoked by our sensitive() calls.
2009-12-02 21:15:56 -05:00
else puts ( "/// Evaluate the model. Application must call when inputs change. \n " );
puts ( "void eval(); \n " );
ofp () -> putsPrivate ( false ); // public:
if ( ! optSystemC ()) puts ( "/// Simulation complete, run final blocks. Application must call on completion. \n " );
puts ( "void final(); \n " );
2006-08-29 00:27:04 +00:00
if ( v3Global . opt . inhibitSim ()) {
2009-12-02 21:15:56 -05:00
puts ( "void inhibitSim(bool flag) { __Vm_inhibitSim=flag; } \t ///< Set true to disable evaluation of module \n " );
2006-08-29 00:27:04 +00:00
}
2009-12-02 21:15:56 -05:00
}
puts ( " \n // INTERNAL METHODS \n " );
if ( modp -> isTop ()) {
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
}
2009-12-02 21:15:56 -05:00
ofp () -> putsPrivate ( false ); // public:
puts ( "void __Vconfigure(" + symClassName () + "* symsp, bool first); \n " );
2006-08-26 11:35:28 +00:00
emitIntFuncDecls ( modp );
if ( ! optSystemPerl () && v3Global . opt . trace ()) {
ofp () -> putsPrivate ( false ); // public:
2010-01-24 18:37:01 -05:00
puts ( "static void traceInit (" + v3Global . opt . traceClassBase () + "* vcdp, void* userthis, uint32_t code); \n " );
puts ( "static void traceFull (" + v3Global . opt . traceClassBase () + "* vcdp, void* userthis, uint32_t code); \n " );
puts ( "static void traceChg (" + v3Global . opt . traceClassBase () + "* 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 " );
}
}
//----------------------------------------------------------------------
2009-11-07 06:20:20 -05:00
void EmitCImp :: emitImp ( AstNodeModule * modp ) {
2006-08-26 11:35:28 +00:00
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
2011-05-20 21:33:31 -04:00
if ( v3Global . dpi ()) {
puts ( " \n " );
puts ( "#include \" verilated_dpi.h \"\n " );
}
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 " );
}
2010-01-21 18:04:36 -05:00
emitTextSection ( AstType :: atSCIMPHDR );
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 ) {
2010-01-21 18:04:36 -05:00
emitTextSection ( AstType :: atSCIMP );
2006-08-26 11:35:28 +00:00
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 " );
}
//######################################################################
2009-11-07 06:20:20 -05:00
void EmitCImp :: main ( AstNodeModule * modp , bool slow , bool fast ) {
2006-08-26 11:35:28 +00:00
// 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 ();
2009-12-02 21:15:56 -05:00
m_ofp -> puts ( "// DESCR" "IPTION: Verilator output: Tracing implementation internals \n " );
2008-11-17 17:13:57 -05:00
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 " );
2010-01-24 18:37:01 -05:00
} else {
puts ( "#include \" verilated_vcd_c.h \"\n " );
2006-08-26 11:35:28 +00:00
}
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 {
2010-01-24 18:37:01 -05:00
puts ( "VerilatedVcdC* tfp, int, int) { \n " );
2006-08-26 11:35:28 +00:00
}
puts ( "tfp->spTrace()->addCallback ("
"&" + topClassName () + "::traceInit"
+ ", &" + topClassName () + "::traceFull"
+ ", &" + topClassName () + "::traceChg, this); \n " );
puts ( "} \n " );
2010-01-24 18:37:01 -05:00
puts ( "void " + topClassName () + "::traceInit("
+ v3Global . opt . traceClassBase () + "* vcdp, void* userthis, uint32_t code) { \n " );
2006-08-26 11:35:28 +00:00
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
2009-09-07 15:55:54 -04:00
puts ( "vcdp->scopeEscape(' '); \n " );
2006-08-30 21:07:55 +00:00
puts ( "t->traceInitThis (vlSymsp, vcdp, code); \n " );
2009-09-07 15:55:54 -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
2010-01-24 18:37:01 -05:00
puts ( "void " + topClassName () + "::traceFull("
+ v3Global . opt . traceClassBase () + "* vcdp, void* userthis, uint32_t code) { \n " );
2006-08-26 11:35:28 +00:00
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 " );
2010-01-24 18:37:01 -05:00
puts ( "void " + topClassName () + "::traceChg("
+ v3Global . opt . traceClassBase () + "* vcdp, void* userthis, uint32_t code) { \n " );
2006-08-26 11:35:28 +00:00
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 ) {
2011-07-24 15:01:51 -04:00
if ( nodep -> isDouble ()) {
puts ( "vcdp->declDouble" );
} else if ( nodep -> isWide ()) {
2006-08-26 11:35:28 +00:00
puts ( "vcdp->declArray" );
} else if ( nodep -> isQuad ()) {
puts ( "vcdp->declQuad " );
2012-03-19 20:25:35 -04:00
} else if ( nodep -> left () || nodep -> right ()) {
2006-08-26 11:35:28 +00:00
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" );
}
2012-03-03 12:10:29 -05:00
if ( ! nodep -> isDouble () // When float/double no longer have widths this can go
2012-03-19 20:25:35 -04:00
&& ( nodep -> left () || nodep -> right ())) {
puts ( "," + cvtToStr ( nodep -> left ()) + "," + cvtToStr ( nodep -> right ()));
2006-08-26 11:35:28 +00:00
}
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" );
2011-07-24 15:01:51 -04:00
if ( nodep -> isDouble ()) {
puts ( "vcdp->" + full + "Double" );
} else 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 " );
2012-03-19 20:25:35 -04:00
} else if ( nodep -> declp () -> left () || nodep -> declp () -> right ()) {
2006-08-26 11:35:28 +00:00
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 );
2012-03-03 12:10:29 -05:00
if ( ! nodep -> isDouble () // When float/double no longer have widths this can go
2012-03-19 20:25:35 -04:00
&& ( nodep -> declp () -> left () || nodep -> declp () -> right () || emitTraceIsScBv ( nodep ))) {
2006-08-26 11:35:28 +00:00
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 ();
puts ( "(" );
2009-07-07 17:51:00 -04:00
if ( emitTraceIsScBv ( nodep )) puts ( "VL_SC_BV_DATAP(" );
2006-08-26 11:35:28 +00:00
varrefp -> iterate ( * this ); // Put var name out
2009-11-04 22:31:53 -05:00
// Tracing only supports 1D arrays
2009-11-06 23:16:06 -05:00
if ( varp -> dtypeSkipRefp () -> castArrayDType ()) {
2006-08-26 11:35:28 +00:00
if ( arrayindex ==- 2 ) puts ( "[i]" );
else if ( arrayindex ==- 1 ) puts ( "[0]" );
else puts ( "[" + cvtToStr ( arrayindex ) + "]" );
}
if ( varp -> isSc ()) puts ( ".read()" );
2009-07-07 17:51:00 -04:00
if ( emitTraceIsScBv ( nodep )) puts ( ")" );
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 );
}
2009-11-07 06:20:20 -05:00
virtual void visit ( AstNodeModule * nodep , AstNUser * ) {
2006-08-26 11:35:28 +00:00
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
2009-11-07 06:20:20 -05:00
for ( AstNodeModule * nodep = v3Global . rootp () -> modulesp (); nodep ; nodep = nodep -> nextp () -> castNodeModule ()) {
2006-08-26 11:35:28 +00:00
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 ()) {
2009-12-03 06:55:29 -05:00
{ EmitCTrace imp ( true ); imp . main (); }
{ EmitCTrace imp ( false ); imp . main (); }
}
}