Пример #1
0
 string bitNames(BitNamesWhich which) {
     string bits="";
     bool prev = false;
     int msb = 0;
     // bit==-1 loops below; we do one extra iteration so end with prev=false
     for (int bit=(m_flags.size()/FLAGS_PER_BIT)-1; bit >= -1; --bit) {
         if (bit>=0
                 && ((which == BN_UNUSED && !usedFlag(bit) && drivenFlag(bit))
                     || (which == BN_UNDRIVEN && usedFlag(bit) && !drivenFlag(bit))
                     || (which == BN_BOTH && !usedFlag(bit) && !drivenFlag(bit)))) {
             if (!prev) {
                 prev=true;
                 msb = bit;
             }
         } else if (prev) {
             AstBasicDType* bdtypep = m_varp->basicp();
             int lsb = bit+1;
             if (bits != "") bits += ",";
             if (lsb==msb) {
                 bits += cvtToStr(lsb+bdtypep->lsb());
             } else {
                 if (bdtypep->littleEndian()) {
                     bits += cvtToStr(lsb+bdtypep->lsb())+":"+cvtToStr(msb+bdtypep->lsb());
                 } else {
                     bits += cvtToStr(msb+bdtypep->lsb())+":"+cvtToStr(lsb+bdtypep->lsb());
                 }
             }
             prev = false;
         }
     }
     return "["+bits+"]";
 }
    // VISITORS
    virtual void visit(AstCell* nodep, AstNUser*) {
	if (nodep->rangep()) {
	    m_cellRangep = nodep->rangep();
	    UINFO(4,"  CELL   "<<nodep<<endl);
	    // Make all of the required clones
	    m_instLsb = m_cellRangep->lsbConst();
	    for (m_instNum = m_instLsb; m_instNum<=m_cellRangep->msbConst(); m_instNum++) {
		AstCell* newp = nodep->cloneTree(false);
		nodep->addNextHere(newp);
		// Remove ranging and fix name
		newp->rangep()->unlinkFrBack()->deleteTree();
		// Somewhat illogically, we need to rename the orignal name of the cell too.
		// as that is the name users expect for dotting
		// The spec says we add [x], but that won't work in C...
		newp->name(newp->name()+"__BRA__"+cvtToStr(m_instNum)+"__KET__");
		newp->origName(newp->origName()+"__BRA__"+cvtToStr(m_instNum)+"__KET__");
		// Fixup pins
		newp->pinsp()->iterateAndNext(*this);
		if (debug()==9) { newp->dumpTree(cout,"newcell: "); cout<<endl; }
	    }

	    // Done.  Delete original
	    m_cellRangep=NULL;
	    nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL;
	}
    }
Пример #3
0
string AstNode::encodeNumber(vlsint64_t num) {
    if (num < 0) {
	return "__02D"+cvtToStr(-num);  // 2D=-
    } else {
	return cvtToStr(num);
    }
}
    string paramSmallName(AstNodeModule* modp, AstVar* varp) {
	if (varp->user4()<=1) {
	    makeSmallNames(modp);
	}
	int index = varp->user4()/256;
	char ch   = varp->user4()&255;
	string st = cvtToStr(ch);
	while (index) {
	    st += cvtToStr(char((index%26)+'A'));
	    index /= 26;
	}
	return st;
    }
Пример #5
0
    void genChangeDet(AstVarScope* vscp) {
#ifdef NEW_ORDERING
	vscp->v3fatalSrc("Not applicable\n");
#endif
	AstVar* varp = vscp->varp();
	vscp->v3warn(IMPERFECTSCH,"Imperfect scheduling of variable: "<<vscp);
	AstUnpackArrayDType* arrayp = varp->dtypeSkipRefp()->castUnpackArrayDType();
	AstStructDType *structp = varp->dtypeSkipRefp()->castStructDType();
	bool isArray = arrayp;
	bool isStruct = structp && structp->packedUnsup();
	int elements = isArray ? arrayp->elementsConst() : 1;
	if (isArray && (elements > DETECTARRAY_MAX_INDEXES)) {
	    vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect more than "<<cvtToStr(DETECTARRAY_MAX_INDEXES)
			 <<" array indexes (probably with UNOPTFLAT warning suppressed): "<<varp->prettyName()<<endl
			 <<vscp->warnMore()
			 <<"... Could recompile with DETECTARRAY_MAX_INDEXES increased to at least "<<cvtToStr(elements));
	} else if (!isArray && !isStruct
		   && !varp->dtypeSkipRefp()->castBasicDType()) {
	    if (debug()) varp->dumpTree(cout,"-DETECTARRAY-");
	    vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable (probably with UNOPTFLAT warning suppressed): "<<varp->prettyName());
	} else {
	    string newvarname = "__Vchglast__"+vscp->scopep()->nameDotless()+"__"+varp->shortName();
	    // Create:  VARREF(_last)
	    //          ASSIGN(VARREF(_last), VARREF(var))
	    //          ...
	    //          CHANGEDET(VARREF(_last), VARREF(var))
	    AstVar* newvarp = new AstVar (varp->fileline(), AstVarType::MODULETEMP, newvarname, varp);
	    m_topModp->addStmtp(newvarp);
	    AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp);
	    m_scopetopp->addVarp(newvscp);
	    for (int index=0; index<elements; ++index) {
		AstChangeDet* changep
		    = new AstChangeDet (vscp->fileline(),
					aselIfNeeded(isArray, index,
						     new AstVarRef(vscp->fileline(), vscp, false)),
					aselIfNeeded(isArray, index,
						     new AstVarRef(vscp->fileline(), newvscp, false)),
					false);
		m_chgFuncp->addStmtsp(changep);
		AstAssign* initp
		    = new AstAssign (vscp->fileline(),
				     aselIfNeeded(isArray, index,
						  new AstVarRef(vscp->fileline(), newvscp, true)),
				     aselIfNeeded(isArray, index,
						  new AstVarRef(vscp->fileline(), vscp, false)));
		m_chgFuncp->addFinalsp(initp);
	    }
	}
    }
Пример #6
0
    virtual void visit(AstPin* nodep, AstNUser*) {
	// Check to see if any output pins have __en pins and create the __en pins to match
	AstVarRef* refp = findVarRef(nodep);

	if (refp && refp->lvalue() && nodep->modVarp()->user1p()) {
	    AstVar* enchildp = (AstVar*)nodep->modVarp()->user1p();
	    UINFO(9, "       Pulling __en var" << enchildp << endl);
	    AstVar* enp = new AstVar(enchildp->fileline(),
				     AstVarType::OUTPUT,
				     enchildp->name()+cvtToStr(m_unique++),
				     enchildp);
	    enp->user2(enchildp->user2());
	    m_modp->addStmtp(enp);
	    AstPin* pinp = new AstPin(nodep->fileline(),
				      nodep->pinNum(),
				      enp->name(),
				      new AstVarRef(nodep->fileline(), enp, true));
	    AstVarRef *rp = findVarRef(pinp);
	    rp->replaceWith(new AstVarRef(nodep->fileline(), enp, true));
	    rp->deleteTree(); rp=NULL;
	    pinp->width(enp->width(),enp->width());  // minwidth==width
	    pinp->modVarp(enchildp);
	    m_cellp->addPinsp(pinp);
	    refp->user1p(enp);
	    refp->varp()->user1p(enp);
	}
	// Simplify interconnect in preperation for V3Inst
	// (This could be a separate visitor, but we're in the neighborhood)
	V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp);
    }
Пример #7
0
    AstVar* createEnableVar(AstNode* outp, AstVarRef* outrefp, AstNode* enrhsp, int width, string suffix="") {
	// this function creates an  __en Var that corresponds to
	// the outp and outrefp and creates an assignw to enrhsp
        AstVar* enp = new AstVar (outrefp->varp()->fileline(),
				  AstVarType::MODULETEMP,
				  outrefp->name() + "__en" + suffix + cvtToStr(m_unique++),
				  AstLogicPacked(), width);
	enp->varType2Out();

	if (enp->width() != enrhsp->width()) {
	    if (enrhsp->width1()) { // it seems from my futzing that the linter guarantees this condition
		enrhsp = new AstReplicate(enrhsp->fileline(), enrhsp,
					  new AstConst(enrhsp->fileline(), V3Number(enrhsp->fileline(), 32, enp->width())));
		enrhsp->width(enp->width(), enp->width());  //minwidth==width
	    } else {
		enrhsp->v3error("Don't know how to deal with selection logic wider than 1 bit");
	    }
	}

	AstNode* newassp = new AstAssignW (enp->fileline(),
					   new AstVarRef (enp->fileline(), enp, true),
					   enrhsp);
	if (debug()>=9) enp->dumpTreeAndNext(cout,"-   cev-out: ");
	if (debug()>=9) newassp->dumpTreeAndNext(cout,"-   cev-out: ");
        m_modp->addStmtp(enp);
        m_modp->addStmtp(newassp);

	outrefp->user1p(enp); // put __en signal into varref for later usage
	outrefp->varp()->user1p(enp); // put __en signal into var as well in the event this is a single lhs driver and this needs passed up one level

	return enp;
    }
Пример #8
0
    virtual void visit(AstRepeat* nodep, AstNUser*) {
	// So later optimizations don't need to deal with them,
	//    REPEAT(count,body) -> loop=count,WHILE(loop>0) { body, loop-- }
	// Note var can be signed or unsigned based on original number.
	AstNode* countp = nodep->countp()->unlinkFrBackWithNext();
   	string name = string("__Vrepeat")+cvtToStr(m_repeatNum++);
	// Spec says value is integral, if negative is ignored
	AstVar* varp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, name,
				  nodep->findSigned32DType());
	varp->usedLoopIdx(true);
	m_modp->addStmtp(varp);
	AstNode* initsp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
					countp);
	AstNode* decp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
				      new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
						 new AstConst(nodep->fileline(), 1)));
	V3Number zero (nodep->fileline(), 32, 0);  zero.isSigned(true);
	AstNode* zerosp = new AstConst(nodep->fileline(), zero);
	AstNode* condp = new AstGtS(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
				    zerosp);
	AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext();
	AstNode* newp = new AstWhile(nodep->fileline(),
				     condp,
				     bodysp,
				     decp);
	initsp = initsp->addNext(newp);
	newp = initsp;
	nodep->replaceWith(newp);
	nodep->deleteTree(); VL_DANGLING(nodep);
    }
Пример #9
0
    AstVar* getBlockTemp(AstNode* nodep) {
	string newvarname = ((string)"__Vtemp"+cvtToStr(m_modp->varNumGetInc()));
	AstVar* varp = new AstVar (nodep->fileline(), AstVarType::STMTTEMP, newvarname,
				   nodep->dtypep());
	m_funcp->addInitsp(varp);
	return varp;
    }
Пример #10
0
    virtual void visit(AstUnpackArrayDType* nodep, AstNUser*) {
	// Note more specific dtypes above
	if (m_traVscp) {
	    if ((int)nodep->arrayUnpackedElements() > v3Global.opt.traceMaxArray()) {
		addIgnore("Wide memory > --trace-max-array ents");
	    } else if (nodep->subDTypep()->skipRefp()->castBasicDType()  // Nothing lower than this array
		       && m_traVscp->dtypep()->skipRefp() == nodep) {  // Nothing above this array
		// Simple 1-D array, use exising V3EmitC runtime loop rather than unrolling
		// This will put "(index)" at end of signal name for us
		addTraceDecl(nodep->declRange());
	    } else {
		// Unroll now, as have no other method to get right signal names
		AstNodeDType* subtypep = nodep->subDTypep()->skipRefp();
		for (int i=nodep->lsb(); i<=nodep->msb(); ++i) {
		    string oldShowname = m_traShowname;
		    AstNode* oldValuep = m_traValuep;
		    {
			m_traShowname += string("(")+cvtToStr(i)+string(")");
			m_traValuep = new AstArraySel(nodep->fileline(), m_traValuep->cloneTree(true),
						      i - nodep->lsb());

			subtypep->accept(*this);
			m_traValuep->deleteTree(); m_traValuep = NULL;
		    }
		    m_traShowname = oldShowname;
		    m_traValuep = oldValuep;
		}
	    }
	}
    }
Пример #11
0
    virtual void visit(AstPackArrayDType* nodep, AstNUser*) {
	if (m_traVscp) {
	    if (!v3Global.opt.traceStructs()) {
		// Everything downstream is packed, so deal with as one trace unit
		// This may not be the nicest for user presentation, but is a much faster way to trace
		addTraceDecl(VNumRange());
	    } else {
		AstNodeDType* subtypep = nodep->subDTypep()->skipRefp();
		for (int i=nodep->lsb(); i<=nodep->msb(); ++i) {
		    string oldShowname = m_traShowname;
		    AstNode* oldValuep = m_traValuep;
		    {
			m_traShowname += string("(")+cvtToStr(i)+string(")");
			m_traValuep = new AstSel(nodep->fileline(), m_traValuep->cloneTree(true),
						 (i - nodep->lsb())*subtypep->width(),
						 subtypep->width());
			subtypep->accept(*this);
			m_traValuep->deleteTree(); m_traValuep = NULL;
		    }
		    m_traShowname = oldShowname;
		    m_traValuep = oldValuep;
		}
	    }
	}
    }
Пример #12
0
    // ACCESSORS
    // Do not make accessor for nodep(),  It may change due to
    // reordering a lower block, but we don't repair it
    virtual string name() const {
	if (m_nodep->name() == "") {
	    return cvtToStr((void*)m_nodep);
	} else {
	    return m_nodep->name();
	}
    }
Пример #13
0
    void createDeepTemp(AstNode* nodep) {
	UINFO(6,"  Deep  "<<nodep<<endl);
	//if (debug()>=9) nodep->dumpTree(cout,"deep:");

	string newvarname = ((string)"__Vdeeptemp"+cvtToStr(m_modp->varNumGetInc()));
	AstVar* varp = new AstVar (nodep->fileline(), AstVarType::STMTTEMP, newvarname,
				   // Width, not widthMin, as we may be in middle of BITSEL expression which
				   // though it's one bit wide, needs the mask in the upper bits.
				   // (Someday we'll have a valid bitmask instead of widths....)
				   // See t_func_crc for an example test that requires this
				   VFlagLogicPacked(), nodep->width());
	if (!m_funcp) nodep->v3fatalSrc("Deep expression not under a function");
	m_funcp->addInitsp(varp);
	// Replace node tree with reference to var
	AstVarRef* newp = new AstVarRef (nodep->fileline(), varp, false);
	nodep->replaceWith(newp);
	// Put assignment before the referencing statement
	AstAssign* assp = new AstAssign (nodep->fileline(),
					 new AstVarRef(nodep->fileline(), varp, true),
					 nodep);
	AstNRelinker linker2;
	m_stmtp->unlinkFrBack(&linker2);
	assp->addNext(m_stmtp);
	linker2.relink(assp);
    }
Пример #14
0
    // METHODS
    string assertDisplayMessage(AstNode* nodep, const string& prefix, const string& message) {
	return (string("[%0t] "+prefix+": ")+nodep->fileline()->filebasename()
		+":"+cvtToStr(nodep->fileline()->lineno())
		+": Assertion failed in %m"
		+((message != "")?": ":"")+message
		+"\\n");
    }
Пример #15
0
const string FileLine::profileFuncname() const {
    // Return string that is OK as a function name - for profiling
    string name  = filebasenameNoExt();
    string::size_type pos;
    while ((pos = name.find_first_not_of("abcdefghijlkmnopqrstuvwxyzABCDEFGHIJLKMNOPQRSTUVWXYZ0123456789_"))
	   != string::npos) {
	name.replace(pos, 1, "_");
    }
    name += "__l"+cvtToStr(lineno());
    return name;
}
string AstVar::scType() const {
    if (isScBigUint()) {
	return (string("sc_biguint<")+cvtToStr(widthMin())+"> ");  // Keep the space so don't get >>
    } else if (isScUint()) {
	return (string("sc_uint<")+cvtToStr(widthMin())+"> ");  // Keep the space so don't get >>
    } else if (isScBv()) {
	return (string("sc_bv<")+cvtToStr(widthMin())+"> ");  // Keep the space so don't get >>
    } else if (widthMin() == 1) {
	return "bool";
    } else if (widthMin() <= VL_WORDSIZE) {
	if (widthMin() <= 8 && v3Global.opt.pinsUint8()) {
	    return "uint8_t";
	} else if (widthMin() <= 16 && v3Global.opt.pinsUint8()) {
	    return "uint16_t";
	} else {
	    return "uint32_t";
	}
    } else {
	return "vluint64_t";
    }
}
    string paramValueNumber(AstNode* nodep) {
	// Given a compilcated object create a number to use for param module assignment
	// Ideally would be relatively stable if design changes (not use pointer value),
	// and must return same value given same input node
	// Return must presently be numberic so doesn't collide with 'small' alphanumeric parameter names
	ValueMap::iterator it = m_valueMap.find(nodep);
	if (it != m_valueMap.end()) {
	    return cvtToStr(it->second);
	} else {
	    static int BUCKETS = 1000;
	    V3Hash hash (nodep->name());
	    int bucket = hash.hshval() % BUCKETS;
	    int offset = 0;
	    NextValueMap::iterator it = m_nextValueMap.find(bucket);
	    if (it != m_nextValueMap.end()) { offset = it->second; it->second = offset + 1; }
	    else { m_nextValueMap.insert(make_pair(bucket, offset + 1)); }
	    int num = bucket + offset * BUCKETS;
	    m_valueMap.insert(make_pair(nodep, num));
	    return cvtToStr(num);
	}
    }
Пример #18
0
    void walkReplace(AstNode* node1p, AstNode* node2p,
		     AstNode* last1p, AstNode* last2p) {  // Final node in linked list, maybe null if all statements to be grabbed
	// Make new function
	string oldname = m_funcp->name();
	string::size_type pos;
	if ((pos=oldname.find("_common")) != string::npos) {
	    oldname.erase(pos);
	}
	if ((pos=oldname.find("__")) != string::npos) {
	    oldname.erase(pos);
	}
	AstCFunc* newfuncp = new AstCFunc(node1p->fileline(),
					  oldname+"_common"+cvtToStr(++m_modNFuncs),
					  NULL);
	m_modp->addStmtp(newfuncp);
	// Create calls
	AstCCall* call1p = new AstCCall(node1p->fileline(), newfuncp);
	AstCCall* call2p = new AstCCall(node2p->fileline(), newfuncp);
	// Grab statement bodies
	AstNRelinker relink1Handle;
	AstNRelinker relink2Handle;
	for (AstNode* nextp, *walkp = node1p; 1; walkp = nextp) {
	    nextp = walkp->nextp();
	    if (walkp==node1p) 	walkp->unlinkFrBack(&relink1Handle);
	    else { walkp->unlinkFrBack(); node1p->addNext(walkp); }
	    if (walkp==last1p) break;
	}
	for (AstNode* nextp, *walkp = node2p; 1; walkp = nextp) {
	    nextp = walkp->nextp();
	    if (walkp==node2p) 	walkp->unlinkFrBack(&relink2Handle);
	    else { walkp->unlinkFrBack(); node2p->addNext(walkp); }
	    if (walkp==last2p) break;
	}
	// Move node1 statements to new function
	newfuncp->addStmtsp(node1p);
	//newfuncp->dumpTree(cout," newfunctree: ");
	// Mark node2 statements as dead
	CombMarkVisitor visitor(node2p);
	pushDeletep(node2p);	// Delete later
	// Link in new function
	relink1Handle.relink(call1p);
	relink2Handle.relink(call2p);
	// Hash the new function
	hashFunctions(newfuncp);
	m_call.addCall(call1p);
	m_call.addCall(call2p);
	// If either new statement makes a func with only a single call, replace
	// the above callers to call it directly
	replaceOnlyCallFunc(call1p); VL_DANGLING(call1p);
	replaceOnlyCallFunc(call2p); VL_DANGLING(call2p);
    }
Пример #19
0
    AstCFunc* newCFuncSub(AstCFunc* basep) {
	string name = basep->name()+"__"+cvtToStr(++m_funcNum);
	AstCFunc* funcp = NULL;
	if (basep->funcType()==AstCFuncType::TRACE_INIT) {
	    funcp = newCFunc(AstCFuncType::TRACE_INIT_SUB, name, basep->slow());
	} else {
	    basep->v3fatalSrc("Strange base function type");
	}
	// cppcheck-suppress nullPointer  // above fatal prevents it
	AstCCall* callp = new AstCCall(funcp->fileline(), funcp);
	callp->argTypes("vlSymsp, vcdp, code");
	basep->addStmtsp(callp);
	return funcp;
    }
Пример #20
0
    AstCFunc* createDeepFunc(AstNode* nodep) {
	AstNRelinker relinkHandle;
	nodep->unlinkFrBack(&relinkHandle);
	// Create function
	string name = m_funcp->name()+"__deep"+cvtToStr(++m_deepNum);
	AstCFunc* funcp = new AstCFunc(nodep->fileline(), name, NULL);
	funcp->argTypes(EmitCBaseVisitor::symClassVar());
	funcp->symProlog(true);
	funcp->slow(m_funcp->slow());
	funcp->addStmtsp(nodep);
	m_modp->addStmtp(funcp);
	// Call it at the point where the body was removed from
	AstCCall* callp = new AstCCall(nodep->fileline(), funcp);
	callp->argTypes("vlSymsp");
	UINFO(6,"      New "<<callp<<endl);
	//
	relinkHandle.relink(callp);
	return funcp;
    }
Пример #21
0
void EmitCInlines::emitInt() {
    string filename = v3Global.opt.makeDir()+"/"+topClassName()+"__Inlines.h";
    newCFile(filename, false/*slow*/, false/*source*/);
    V3OutCFile hf (filename);
    m_ofp = &hf;

    ofp()->putsHeader();
    puts("#ifndef _"+topClassName()+"__Inlines_H_\n");
    puts("#define _"+topClassName()+"__Inlines_H_\n");
    puts("\n");

    puts("#include \"verilated.h\"\n");

    puts("\n//======================\n\n");

    for (unsigned words=0; words<m_wordWidths.size(); words++) {
	if (m_wordWidths.at(words)) {
	    puts("#ifndef VL_HAVE_CONST_W_"+cvtToStr(words)+"X\n");
	    puts("# define VL_HAVE_CONST_W_"+cvtToStr(words)+"X\n");
	    puts("static inline WDataOutP VL_CONST_W_"+cvtToStr(words)+"X(int obits, WDataOutP o\n");
	    puts("\t");
	    for (int i=words-1; i>=0; --i) {
		puts(",IData d"+cvtToStr(i));
		if (i && (i % 8 == 0)) puts("\n\t");
	    }
	    puts(") {\n");
	    puts("   ");
	    for (int i=words-1; i>=0; --i) {
		puts(" o["+cvtToStr(i)+"]=d"+cvtToStr(i)+";");
		if (i && (i % 8 == 0)) puts("\n   ");
	    }
	    puts("\n");
	    puts("    for(int i="+cvtToStr(words)+";i<VL_WORDS_I(obits);i++) o[i] = (IData)0x0;\n");
	    puts("    return o;\n");
	    puts("}\n");
	    puts("#endif\n");
	    puts("\n");
	}
    }

    puts("//======================\n\n");
    puts("#endif  /*guard*/\n");
}
string AstVar::vlArgType(bool named, bool forReturn, bool forFunc) const {
    if (forReturn) named=false;
    if (forReturn) v3fatalSrc("verilator internal data is never passed as return, but as first argument");
    string arg;
    if (isWide() && isInOnly()) arg += "const ";
    AstBasicDType* bdtypep = basicp();
    bool strtype = bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::STRING;
    if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::CHARPTR) {
	arg += "const char*";
    } else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::SCOPEPTR) {
	arg += "const VerilatedScope*";
    } else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::DOUBLE) {
	arg += "double";
    } else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::FLOAT) {
	arg += "float";
    } else if (strtype) {
	if (isInOnly()) arg += "const ";
	arg += "string";
    } else if (widthMin() <= 8) {
	arg += "CData";
    } else if (widthMin() <= 16) {
	arg += "SData";
    } else if (widthMin() <= VL_WORDSIZE) {
	arg += "IData";
    } else if (isQuad()) {
	arg += "QData";
    } else if (isWide()) {
	arg += "WData";  // []'s added later
    }
    if (isWide() && !strtype) {
	arg += " (& "+name();
	arg += ")["+cvtToStr(widthWords())+"]";
    } else {
	if (forFunc && (isOutput() || (strtype && isInput()))) arg += "&";
	if (named) arg += " "+name();
    }
    return arg;
}
Пример #23
0
    virtual void visit(AstEnumItem* nodep, AstNUser*) {
	// Expand ranges
	cleanFileline(nodep);
	nodep->iterateChildren(*this);
	if (nodep->rangep()) {
	    if (!nodep->rangep()->msbp()->castConst()
		|| !nodep->rangep()->lsbp()->castConst()) nodep->v3error("Enum ranges must be integral, per spec");
	    int msb = nodep->rangep()->msbConst();
	    int lsb = nodep->rangep()->lsbConst();
	    int increment = (msb > lsb) ? -1 : 1;
	    int offset_from_init = 0;
	    AstNode* addp = NULL;
	    for (int i=msb; i!=(lsb+increment); i+=increment, offset_from_init++) {
		string name = nodep->name() + cvtToStr(i);
		AstNode* valuep = NULL;
		if (nodep->valuep()) valuep = new AstAdd(nodep->fileline(), nodep->valuep()->cloneTree(true),
							 new AstConst(nodep->fileline(), AstConst::Unsized32(), offset_from_init));
		addp = addp->addNextNull(new AstEnumItem(nodep->fileline(), name, NULL, valuep));
	    }
	    nodep->replaceWith(addp);
	    nodep->deleteTree();
	}
    }
string AstVar::cPubArgType(bool named, bool forReturn) const {
    if (forReturn) named=false;
    string arg;
    if (isWide() && isInOnly()) arg += "const ";
    if (widthMin() == 1) {
	arg += "bool";
    } else if (widthMin() <= VL_WORDSIZE) {
	arg += "uint32_t";
    } else if (isWide()) {
	arg += "uint32_t";  // []'s added later
    } else {
	arg += "vluint64_t";
    }
    if (isWide()) {
	if (forReturn) v3error("Unsupported: Public functions with >64 bit outputs; make an output of a public task instead");
	arg += " (& "+name();
	arg += ")["+cvtToStr(widthWords())+"]";
    } else {
	if (isOutput() && !forReturn) arg += "&";
	if (named) arg += " "+name();
    }
    return arg;
}
Пример #25
0
 // ACCESSORS
 virtual string name() const { return (cvtToStr((void*)m_nodep)+"@"+scopep()->prettyName()); }
Пример #26
0
 virtual string name() const { return (cvtToStr((void*)m_varScp)+" "+varScp()->name()); }
Пример #27
0
string FileLine::ascii() const {
    return filename()+":"+cvtToStr(lineno());
}
    virtual void visit(AstSenItem* nodep, AstNUser*) {
	// Remove bit selects, and bark if it's not a simple variable
	nodep->iterateChildren(*this);
	if (nodep->isClocked()) {
	    // If it's not a simple variable wrap in a temporary
	    // This is a bit unfortunate as we haven't done width resolution
	    // and any width errors will look a bit odd, but it works.
	    AstNode* sensp = nodep->sensp();
	    if (sensp
		&& !sensp->castNodeVarRef()
		&& !sensp->castConst()) {
		// Make a new temp wire
		string newvarname = "__Vsenitemexpr"+cvtToStr(++m_senitemCvtNum);
		AstVar* newvarp = new AstVar (sensp->fileline(), AstVarType::MODULETEMP, newvarname,
					      VFlagLogicPacked(), 1);
		// We can't just add under the module, because we may be inside a generate, begin, etc.
		// We know a SenItem should be under a SenTree/Always etc, we we'll just hunt upwards
		AstNode* addwherep = nodep;  // Add to this element's next
		while (addwherep->castSenItem()
		       || addwherep->castSenTree()) {
		    addwherep = addwherep->backp();
		}
		if (!addwherep->castAlways()) {  // Assertion perhaps?
		    sensp->v3error("Unsupported: Non-single-bit pos/negedge clock statement under some complicated block");
		    addwherep = m_modp;
		}
		addwherep->addNext(newvarp);

		sensp->replaceWith(new AstVarRef (sensp->fileline(), newvarp, false));
		AstAssignW* assignp = new AstAssignW
		    (sensp->fileline(),
		     new AstVarRef(sensp->fileline(), newvarp, true),
		     sensp);
		addwherep->addNext(assignp);
	    }
	} else {  // Old V1995 sensitivity list; we'll probably mostly ignore
	    bool did=1;
	    while (did) {
		did=0;
		if (AstNodeSel* selp = nodep->sensp()->castNodeSel()) {
		    AstNode* fromp = selp->fromp()->unlinkFrBack();
		    selp->replaceWith(fromp); selp->deleteTree(); selp=NULL;
		    did=1;
		}
		// NodeSel doesn't include AstSel....
		if (AstSel* selp = nodep->sensp()->castSel()) {
		    AstNode* fromp = selp->fromp()->unlinkFrBack();
		    selp->replaceWith(fromp); selp->deleteTree(); selp=NULL;
		    did=1;
		}
		if (AstNodePreSel* selp = nodep->sensp()->castNodePreSel()) {
		    AstNode* fromp = selp->lhsp()->unlinkFrBack();
		    selp->replaceWith(fromp); selp->deleteTree(); selp=NULL;
		    did=1;
		}
	    }
	}
	if (!nodep->sensp()->castNodeVarRef()
	    && !nodep->sensp()->castEnumItemRef()) {  // V3Const will cleanup
	    if (debug()) nodep->dumpTree(cout,"-tree: ");
	    nodep->v3error("Unsupported: Complex statement in sensitivity list");
	}
    }
void ParamVisitor::visitCell(AstCell* nodep) {
    // Cell: Check for parameters in the instantiation.
    nodep->iterateChildren(*this);
    if (!nodep->modp()) nodep->v3fatalSrc("Not linked?");
    if (nodep->paramsp()
	|| 1  // Need to look for interfaces; could track when one exists, but should be harmless to always do this
	) {
	UINFO(4,"De-parameterize: "<<nodep<<endl);
	// Create new module name with _'s between the constants
	if (debug()>=10) nodep->dumpTree(cout,"-cell:\t");
	// Evaluate all module constants
	V3Const::constifyParamsEdit(nodep);

	// Make sure constification worked
	// Must be a separate loop, as constant conversion may have changed some pointers.
	//if (debug()) nodep->dumpTree(cout,"-cel2:\t");
	string longname = nodep->modp()->name();
	bool any_overrides = false;
	longname += "_";
	if (debug()>8) nodep->paramsp()->dumpTreeAndNext(cout,"-cellparams:\t");
	for (AstPin* pinp = nodep->paramsp(); pinp; pinp=pinp->nextp()->castPin()) {
	    if (!pinp->exprp()) continue; // No-connect
	    AstVar* modvarp = pinp->modVarp();
	    if (!modvarp) {
		pinp->v3error("Parameter not found in sub-module: Param "<<pinp->name()<<" of "<<nodep->prettyName());
	    } else if (!modvarp->isGParam()) {
		pinp->v3error("Attempted parameter setting of non-parameter: Param "<<pinp->name()<<" of "<<nodep->prettyName());
	    } else {
		AstConst* constp = pinp->exprp()->castConst();
		AstConst* origconstp = modvarp->valuep()->castConst();
		if (!constp) {
		    //if (debug()) pinp->dumpTree(cout,"error:");
		    pinp->v3error("Can't convert defparam value to constant: Param "<<pinp->name()<<" of "<<nodep->prettyName());
		    pinp->exprp()->replaceWith(new AstConst(pinp->fileline(), V3Number(pinp->fileline(), modvarp->width(), 0)));
		} else if (origconstp && constp->sameTree(origconstp)) {
		    // Setting parameter to its default value.  Just ignore it.
		    // This prevents making additional modules, and makes coverage more
		    // obvious as it won't show up under a unique module page name.
		} else {
		    longname += "_" + paramSmallName(nodep->modp(),pinp->modVarp())+constp->num().ascii(false);
		    any_overrides = true;
		}
	    }
	}
	IfaceRefRefs ifaceRefRefs;
	for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) {
	    AstVar* modvarp = pinp->modVarp();
	    if (modvarp->isIfaceRef()) {
		AstIfaceRefDType* portIrefp = modvarp->subDTypep()->castIfaceRefDType();
		//UINFO(9,"     portIfaceRef "<<portIrefp<<endl);
		if (!pinp->exprp()
		    || !pinp->exprp()->castVarRef()
		    || !pinp->exprp()->castVarRef()->varp()
		    || !pinp->exprp()->castVarRef()->varp()->subDTypep()
		    || !pinp->exprp()->castVarRef()->varp()->subDTypep()->castIfaceRefDType()) {
		    pinp->v3error("Interface port '"<<modvarp->prettyName()<<"' is not connected to interface/modport pin expression");
		} else {
		    AstIfaceRefDType* pinIrefp = pinp->exprp()->castVarRef()->varp()->subDTypep()->castIfaceRefDType();
		    //UINFO(9,"     pinIfaceRef "<<pinIrefp<<endl);
		    if (portIrefp->ifaceViaCellp() != pinIrefp->ifaceViaCellp()) {
			UINFO(9,"     IfaceRefDType needs reconnect  "<<pinIrefp<<endl);
			longname += "_" + paramSmallName(nodep->modp(),pinp->modVarp())+paramValueNumber(pinIrefp);
			any_overrides = true;
			ifaceRefRefs.push_back(make_pair(portIrefp,pinIrefp));
		    }
		}
	    }
	}

	if (!any_overrides) {
	    UINFO(8,"Cell parameters all match original values, skipping expansion.\n");
	} else {
	    // If the name is very long, we don't want to overwhelm the filename limit
	    // We don't do this always, as it aids debugability to have intuitive naming.
	    // TODO can use new V3Name hash replacement instead of this
	    string newname = longname;
	    if (longname.length()>30) {
		LongMap::iterator iter = m_longMap.find(longname);
		if (iter != m_longMap.end()) {
		    newname = iter->second;
		} else {
		    newname = nodep->modp()->name();
		    newname += "__pi"+cvtToStr(++m_longId);  // We use all upper case above, so lower here can't conflict
		    m_longMap.insert(make_pair(longname, newname));
		}
	    }
	    UINFO(4,"Name: "<<nodep->modp()->name()<<"->"<<longname<<"->"<<newname<<endl);

	    //
	    // Already made this flavor?
	    AstNodeModule* modp = NULL;
	    ModNameMap::iterator iter = m_modNameMap.find(newname);
	    if (iter != m_modNameMap.end()) modp = iter->second.m_modp;
	    if (!modp) {
		// Deep clone of new module
		// Note all module internal variables will be re-linked to the new modules by clone
		// However links outside the module (like on the upper cells) will not.
		modp = nodep->modp()->cloneTree(false);
		modp->name(newname);
		modp->user5(false); // We need to re-recurse this module once changed
		nodep->modp()->addNextHere(modp);  // Keep tree sorted by cell occurrences

		m_modNameMap.insert(make_pair(modp->name(), ModInfo(modp)));
		iter = m_modNameMap.find(newname);
		VarCloneMap* clonemapp = &(iter->second.m_cloneMap);
		UINFO(4,"     De-parameterize to new: "<<modp<<endl);

		// Grab all I/O so we can remap our pins later
		// Note we allow multiple users of a parameterized model, thus we need to stash this info.
		for (AstNode* stmtp=modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
		    if (AstVar* varp = stmtp->castVar()) {
			if (varp->isIO() || varp->isGParam() || varp->isIfaceRef()) {
			    // Cloning saved a pointer to the new node for us, so just follow that link.
			    AstVar* oldvarp = varp->clonep()->castVar();
			    //UINFO(8,"Clone list 0x"<<hex<<(uint32_t)oldvarp<<" -> 0x"<<(uint32_t)varp<<endl);
			    clonemapp->insert(make_pair(oldvarp, varp));
			}
		    }
		}

		// Relink parameter vars to the new module
		relinkPins(clonemapp, nodep->paramsp());

		// Fix any interface references
		for (IfaceRefRefs::iterator it=ifaceRefRefs.begin(); it!=ifaceRefRefs.end(); ++it) {
		    AstIfaceRefDType* portIrefp = it->first;
		    AstIfaceRefDType* pinIrefp = it->second;
		    AstIfaceRefDType* cloneIrefp = portIrefp->clonep()->castIfaceRefDType();
		    UINFO(8,"     IfaceOld "<<portIrefp<<endl);
		    UINFO(8,"     IfaceTo  "<<pinIrefp<<endl);
		    if (!cloneIrefp) portIrefp->v3fatalSrc("parameter clone didn't hit AstIfaceRefDType");
		    UINFO(8,"     IfaceClo "<<cloneIrefp<<endl);
		    cloneIrefp->ifacep(pinIrefp->ifaceViaCellp());
		    UINFO(8,"     IfaceNew "<<cloneIrefp<<endl);
		}

		// Assign parameters to the constants specified
		// DOES clone() so must be finished with module clonep() before here
		for (AstPin* pinp = nodep->paramsp(); pinp; pinp=pinp->nextp()->castPin()) {
		    AstVar* modvarp = pinp->modVarp();
		    if (modvarp && pinp->exprp()) {
			AstConst* constp = pinp->exprp()->castConst();
			// Remove any existing parameter
			if (modvarp->valuep()) modvarp->valuep()->unlinkFrBack()->deleteTree();
			// Set this parameter to value requested by cell
			modvarp->valuep(constp->cloneTree(false));
		    }
		}
	    } else {
		UINFO(4,"     De-parameterize to old: "<<modp<<endl);
	    }

	    // Have child use this module instead.
	    nodep->modp(modp);
	    nodep->modName(newname);

	    // We need to relink the pins to the new module
	    VarCloneMap* clonemapp = &(iter->second.m_cloneMap);
	    relinkPins(clonemapp, nodep->pinsp());
	    UINFO(8,"     Done with "<<modp<<endl);
	} // if any_overrides

	// Delete the parameters from the cell; they're not relevant any longer.
	if (nodep->paramsp()) nodep->paramsp()->unlinkFrBackWithNext()->deleteTree();
	UINFO(8,"     Done with "<<nodep<<endl);
	//if (debug()>=10) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param-out.tree"));
    }

    // Now remember to process the child module at the end of the module
    m_todoModps.insert(make_pair(nodep->modp()->level(),nodep->modp()));
}
Пример #30
0
    virtual void visit(AstCell* nodep, AstNUser*) {
	// Cell: Resolve its filename.  If necessary, parse it.
	if (nodep->user1SetOnce()) return;  // AstBind and AstNodeModule may call a cell twice
	if (!nodep->modp()) {
	    UINFO(4,"Link Cell: "<<nodep<<endl);
	    // Use findIdFallback instead of findIdFlat; it doesn't matter for now
	    // but we might support modules-under-modules someday.
	    AstNodeModule* modp = resolveModule(nodep,nodep->modName());
	    if (modp) {
		nodep->modp(modp);
		// Track module depths, so can sort list from parent down to children
		new V3GraphEdge(&m_graph, vertex(m_modp), vertex(modp), 1, false);
	    }
	}
	// Remove AstCell(AstPin("",NULL)), it's a side effect of how we parse "()"
	// the empty middle is identical to the empty rule that must find pins in "(,)".
	if (nodep->pinsp() && !nodep->pinsp()->nextp()
	    && nodep->pinsp()->name() == ""
	    && !nodep->pinsp()->exprp()) {
	    pushDeletep(nodep->pinsp()->unlinkFrBackWithNext());
	}
	if (nodep->paramsp() && !nodep->paramsp()->nextp()
	    && nodep->paramsp()->name() == ""
	    && !nodep->paramsp()->exprp()) {
	    pushDeletep(nodep->paramsp()->unlinkFrBackWithNext());
	}
	// Convert .* to list of pins
	bool pinStar = false;
	for (AstPin* nextp, *pinp = nodep->pinsp(); pinp; pinp=nextp) {
	    nextp = pinp->nextp()->castPin();
	    if (pinp->dotStar()) {
		if (pinStar) pinp->v3error("Duplicate .* in a cell");
		pinStar = true;
		// Done with this fake pin
		pinp->unlinkFrBack()->deleteTree(); pinp=NULL;
	    }
	}
	// Convert unnamed pins to pin number based assignments
	for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) {
	    if (pinp->name()=="") pinp->name("__pinNumber"+cvtToStr(pinp->pinNum()));
	}
	for (AstPin* pinp = nodep->paramsp(); pinp; pinp=pinp->nextp()->castPin()) {
	    if (pinp->name()=="") pinp->name("__paramNumber"+cvtToStr(pinp->pinNum()));
	}
	if (nodep->modp()) {
	    // Note what pins exist
	    set<string> ports;	// Symbol table of all connected port names
	    for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) {
		if (pinp->name()=="") pinp->v3error("Connect by position is illegal in .* connected cells");
		if (!pinp->exprp()) pinp->v3warn(PINNOCONNECT,"Cell pin is not connected: "<<pinp->prettyName());
		if (ports.find(pinp->name()) == ports.end()) {
		    ports.insert(pinp->name());
		}
	    }
	    // We search ports, rather than in/out declarations as they aren't resolved yet,
	    // and it's easier to do it now than in V3LinkDot when we'd need to repeat steps.
	    for (AstNode* portnodep = nodep->modp()->stmtsp(); portnodep; portnodep=portnodep->nextp()) {
		if (AstPort* portp = portnodep->castPort()) {
		    if (ports.find(portp->name()) == ports.end()
			&& ports.find("__pinNumber"+cvtToStr(portp->pinNum())) == ports.end()) {
			if (pinStar) {
			    UINFO(9,"    need .* PORT  "<<portp<<endl);
			    // Create any not already connected
			    AstPin* newp = new AstPin(nodep->fileline(),0,portp->name(),
						      new AstVarRef(nodep->fileline(),portp->name(),false));
			    newp->svImplicit(true);
			    nodep->addPinsp(newp);
			} else {  // warn on the CELL that needs it, not the port
			    nodep->v3warn(PINMISSING, "Cell has missing pin: "<<portp->prettyName());
			    AstPin* newp = new AstPin(nodep->fileline(),0,portp->name(),NULL);
			    nodep->addPinsp(newp);
			}
		    }
		}
	    }
	}
	if (nodep->modp()->castIface()) {
	    // Cell really is the parent's instantiation of an interface, not a normal module
	    // Make sure we have a variable to refer to this cell, so can <ifacename>.<innermember>
	    // in the same way that a child does.  Rename though to avoid conflict with cell.
	    // This is quite similar to how classes work; when unpacked classes are better supported
	    // may remap interfaces to be more like a class.
	    if (!nodep->hasIfaceVar()) {
		string varName = nodep->name()+"__Viftop";  // V3LinkDot looks for this naming
		AstIfaceRefDType* idtypep = new AstIfaceRefDType(nodep->fileline(), nodep->name(), nodep->modp()->name());
		idtypep->cellp(nodep);  // Only set when real parent cell known
		idtypep->ifacep(NULL);  // cellp overrides
		AstVar* varp = new AstVar(nodep->fileline(), AstVarType::IFACEREF, varName, VFlagChildDType(), idtypep);
		varp->isIfaceParent(true);
		nodep->addNextHere(varp);
		nodep->hasIfaceVar(true);
	    }
	}
	if (nodep->modp()) {
	    nodep->iterateChildren(*this);
	}
	UINFO(4," Link Cell done: "<<nodep<<endl);
    }