Beispiel #1
0
    AstArraySel* insertImplicit(AstNode* nodep, unsigned start, unsigned count) {
	// Insert any implicit slices as explicit slices (ArraySel nodes).
	// Return a new pointer to replace nodep() in the ArraySel.
	UINFO(9,"  insertImplicit (start="<<start<<",c="<<count<<") "<<nodep<<endl);
	AstVarRef* refp = nodep->user1p()->castNode()->castVarRef();
	if (!refp) nodep->v3fatalSrc("No VarRef in user1 of node "<<nodep);
	AstVar* varp = refp->varp();
	AstNode* topp = nodep;
	for (unsigned i = start; i < start + count; ++i) {
	    AstNodeDType* dtypep = varp->dtypep()->dtypeDimensionp(i-1);
	    AstUnpackArrayDType* adtypep = dtypep->castUnpackArrayDType();
	    if (!adtypep) nodep->v3fatalSrc("insertImplicit tried to expand an array without an ArrayDType");
	    vlsint32_t msb = adtypep->msb();
	    vlsint32_t lsb = adtypep->lsb();
	    if (lsb > msb) {
		// Below code assumes big bit endian; just works out if we swap
		int x = msb; msb = lsb; lsb = x;
	    }
	    UINFO(9,"    ArraySel-child: "<<topp<<endl);
	    AstArraySel* newp = new AstArraySel(nodep->fileline(), topp,
						// "lsb-lsb": Arrays are zero-based so index 0 is always lsb
						new AstConst(nodep->fileline(), lsb-lsb));
	    if (!newp->dtypep()) {
		newp->v3fatalSrc("ArraySel dtyping failed when resolving slice");  // see ArraySel constructor
	    }
	    newp->user1p(refp);
	    newp->start(lsb);
	    newp->length(msb - lsb + 1);
	    topp = newp;
	}
	return topp->castArraySel();
    }
Beispiel #2
0
    // VISITORS
    virtual void visit(AstArraySel* nodep, AstNUser*) {
	if (!nodep->backp()->castArraySel()) {
	    // This is the top of an ArraySel, setup for iteration
	    m_refp = nodep->user1p()->castNode()->castVarRef();
	    m_vecIdx += 1;
	    if (m_vecIdx == (int)m_selBits.size()) {
		m_selBits.push_back(vector<unsigned>());
		AstVar* varp = m_refp->varp();
		pair<uint32_t,uint32_t> arrDim = varp->dtypep()->dimensions(false);
		uint32_t dimensions = arrDim.second;
		// for 3-dimensions we want m_selBits[m_vecIdx]=[0,0,0]
		for (uint32_t i = 0; i < dimensions; ++i) {
		    m_selBits[m_vecIdx].push_back(0);
		}
	    }
	}
	nodep->iterateChildren(*this);
	if (nodep->fromp()->castVarRef()) {
	    m_depth = 0;
	} else {
	    ++m_depth;
	}
	// Check if m_selBits has overflowed
	if (m_selBits[m_vecIdx][m_depth] >= nodep->length()) {
	    m_selBits[m_vecIdx][m_depth] = 0;
	    if (m_depth + 1 < m_selBits[m_vecIdx].size())
		m_selBits[m_vecIdx][m_depth+1] += 1;
	}
	// Reassign the bitp()
	if (nodep->length() > 1) {
	    if (AstConst* bitp = nodep->bitp()->castConst()) {
		AstUnpackArrayDType* adtypep = nodep->fromp()->dtypep()->skipRefp()->castUnpackArrayDType();
		if (!adtypep) nodep->v3fatalSrc("slice select tried to expand an array without an ArrayDType");
		unsigned idx = nodep->start() + m_selBits[m_vecIdx][m_depth] - adtypep->lsb();
		AstNode* constp = new AstConst(bitp->fileline(), V3Number(bitp->fileline(), bitp->castConst()->num().width(), idx));
		bitp->replaceWith(constp);
	    } else {
		nodep->v3error("Unsupported: Only constants supported in slices");
	    }
	}
	if (!nodep->backp()->castArraySel()) {
	    // Top ArraySel, increment m_selBits
	    m_selBits[m_vecIdx][0] += 1;
	}
	nodep->length(1);
    }
Beispiel #3
0
void V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstNodeModule* modp) {
    // If a pin connection is "simple" leave it as-is
    // Else create a intermediate wire to perform the interconnect
    // Note this module calles cloneTree() via new AstVar
    AstVar* pinVarp = pinp->modVarp();
    AstVarRef* connectRefp = pinp->exprp()->castVarRef();
    AstBasicDType* pinBasicp = pinVarp->dtypep()->basicp();  // Maybe NULL
    AstBasicDType* connBasicp = NULL;
    if (connectRefp) connBasicp = connectRefp->varp()->dtypep()->basicp();
    //
    if (connectRefp
	&& connectRefp->varp()->dtypep()->sameTree(pinVarp->dtypep())
	&& !connectRefp->varp()->isSc()) { // Need the signal as a 'shell' to convert types
	// Done.  Same data type
    } else if (connBasicp
	       && pinBasicp
	       && connBasicp->width() == pinBasicp->width()
	       && connBasicp->lsb() == pinBasicp->lsb()
	       && !connectRefp->varp()->isSc()	// Need the signal as a 'shell' to convert types
	       && pinp->width() == pinVarp->width()
	       && 1) {
	// Done. One to one interconnect won't need a temporary variable.
    } else if (pinp->exprp()->castConst()) {
	// Done. Constant.
    } else {
	// Make a new temp wire
	//if (1||debug()>=9) { pinp->dumpTree(cout,"in_pin:"); }
	AstAssignW* assignp = NULL;
	AstNode* pinexprp = pinp->exprp()->unlinkFrBack();
	string newvarname = "__Vcellinp__"+cellp->name()+"__"+pinp->name();
	AstVar* newvarp = new AstVar (pinVarp->fileline(), AstVarType::MODULETEMP, newvarname, pinVarp);
	modp->addStmtp(newvarp);
	if (pinVarp->isInout()) {
	    pinVarp->v3fatalSrc("Unsupported: Inout connections to pins must be direct one-to-one connection (without any expression)");
	} else if (pinVarp->isOutput()) {
	    // See also V3Inst
	    AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, false);
	    if (pinp->width() > rhsp->width()) {
		if (rhsp->isSigned()) {
		    rhsp = new AstExtendS(pinp->fileline(), rhsp);
		} else {
		    rhsp = new AstExtend (pinp->fileline(), rhsp);
		}
	    } else if (pinp->width() < rhsp->width()) {
		rhsp = new AstSel    (pinp->fileline(), rhsp, 0, pinp->width());
	    }
	    rhsp->widthSignedFrom(pinp);
	    assignp = new AstAssignW (pinp->fileline(), pinexprp, rhsp);
	    pinp->exprp(new AstVarRef (pinexprp->fileline(), newvarp, true));
	} else {
	    // V3 width should have range/extended to make the widths correct
	    if (pinexprp->width() != pinVarp->width()) pinp->v3fatalSrc("Input pin width mismatch");
	    assignp = new AstAssignW (pinp->fileline(),
				      new AstVarRef(pinp->fileline(), newvarp, true),
				      pinexprp);
	    pinp->exprp(new AstVarRef (pinexprp->fileline(), newvarp, false));
	}
	pinp->widthSignedFrom(pinp->exprp());
	if (assignp) modp->addStmtp(assignp);
	//if (1||debug()) { pinp->dumpTree(cout,"  out:"); }
	//if (1||debug()) { assignp->dumpTree(cout," aout:"); }
    }
}
    static AstAssignW* pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstNodeModule*,
					  bool forTristate, bool alwaysCvt) {
	// If a pin connection is "simple" leave it as-is
	// Else create a intermediate wire to perform the interconnect
	// Return the new assignment, if one was made
	// Note this module calles cloneTree() via new AstVar
	AstVar* pinVarp = pinp->modVarp();
	AstVarRef* connectRefp = pinp->exprp()->castVarRef();
	AstBasicDType* pinBasicp = pinVarp->dtypep()->basicp();  // Maybe NULL
	AstBasicDType* connBasicp = NULL;
	AstAssignW* assignp = NULL;
	if (connectRefp) connBasicp = connectRefp->varp()->dtypep()->basicp();
	//
	if (!alwaysCvt
	    && connectRefp
	    && connectRefp->varp()->dtypep()->sameTree(pinVarp->dtypep())
	    && !connectRefp->varp()->isSc()) { // Need the signal as a 'shell' to convert types
	    // Done. Same data type
	} else if (!alwaysCvt
		   && connectRefp
		   && connectRefp->varp()->isIfaceRef()) {
	    // Done. Interface
	} else if (!alwaysCvt
		   && connBasicp
		   && pinBasicp
		   && connBasicp->width() == pinBasicp->width()
		   && connBasicp->lsb() == pinBasicp->lsb()
		   && !connectRefp->varp()->isSc()	// Need the signal as a 'shell' to convert types
		   && connBasicp->width() == pinVarp->width()
		   && 1) {
	    // Done. One to one interconnect won't need a temporary variable.
	} else if (!alwaysCvt && !forTristate && pinp->exprp()->castConst()) {
	    // Done. Constant.
	} else {
	    // Make a new temp wire
	    //if (1||debug()>=9) { pinp->dumpTree(cout,"-in_pin:"); }
	    AstNode* pinexprp = pinp->exprp()->unlinkFrBack();
	    string newvarname = ((string)(pinVarp->isOutput() ? "__Vcellout" : "__Vcellinp")
				 +(forTristate?"t":"")  // Prevent name conflict if both tri & non-tri add signals
				 +"__"+cellp->name()+"__"+pinp->name());
	    AstVar* newvarp = new AstVar (pinVarp->fileline(), AstVarType::MODULETEMP, newvarname, pinVarp);
	    // Important to add statement next to cell, in case there is a generate with same named cell
	    cellp->addNextHere(newvarp);
	    if (pinVarp->isInout()) {
		pinVarp->v3fatalSrc("Unsupported: Inout connections to pins must be direct one-to-one connection (without any expression)");
	    } else if (pinVarp->isOutput()) {
		// See also V3Inst
		AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, false);
		UINFO(5,"pinRecon width "<<pinVarp->width()<<" >? "<<rhsp->width()<<" >? "<<pinexprp->width()<<endl);
		rhsp = extendOrSel (pinp->fileline(), rhsp, pinVarp);
		pinp->exprp(new AstVarRef (newvarp->fileline(), newvarp, true));
		AstNode* rhsSelp = extendOrSel (pinp->fileline(), rhsp, pinexprp);
		assignp = new AstAssignW (pinp->fileline(), pinexprp, rhsSelp);
	    } else {
		// V3 width should have range/extended to make the widths correct
		assignp = new AstAssignW (pinp->fileline(),
					  new AstVarRef(pinp->fileline(), newvarp, true),
					  pinexprp);
		pinp->exprp(new AstVarRef (pinexprp->fileline(), newvarp, false));
	    }
	    if (assignp) cellp->addNextHere(assignp);
	    //if (debug()) { pinp->dumpTree(cout,"-  out:"); }
	    //if (debug()) { assignp->dumpTree(cout,"- aout:"); }
	}
	return assignp;
    }
Beispiel #5
0
void EmitCSyms::emitSymImp() {
    UINFO(6,__FUNCTION__<<": "<<endl);
    string filename = v3Global.opt.makeDir()+"/"+symClassName()+".cpp";
    AstCFile* cfilep = newCFile(filename, true/*slow*/, true/*source*/);
    cfilep->support(true);
    V3OutCFile cf (filename);
    m_ofp = &cf;
    ofp()->putsHeader();
    puts("// DESCR" "IPTION: Verilator output: Symbol table implementation internals\n");
    puts("\n");

    // Includes
    puts("#include \""+symClassName()+".h\"\n");
    for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; nodep=nodep->nextp()->castNodeModule()) {
	puts("#include \""+modClassName(nodep)+".h\"\n");
    }

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

    puts("\n// FUNCTIONS\n");
    puts(symClassName()+"::"+symClassName()+"("+topClassName()+"* topp, const char* namep)\n");
    puts("\t// Setup locals\n");
    puts("\t: __Vm_namep(namep)\n");	// No leak, as we get destroyed when the top is destroyed
    puts("\t, __Vm_activity(false)\n");
    puts("\t, __Vm_didInit(false)\n");
    puts("\t// Setup submodule names\n");
    char comma=',';
    for (vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
	AstScope* scopep = it->first;  AstNodeModule* modp = it->second;
	if (modp->isTop()) {
	} else {
	    ofp()->printf("\t%c %-30s ", comma, scopep->nameDotless().c_str());
	    puts("(Verilated::catName(topp->name(),");
	    // The "." is added by catName
	    putsQuoted(scopep->prettyName());
	    puts("))\n");
	    comma=',';
	}
    }
    puts("{\n");

    puts("// Pointer to top level\n");
    puts("TOPp = topp;\n");
    puts("// Setup each module's pointers to their submodules\n");
    for (vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
	AstScope* scopep = it->first;  AstNodeModule* modp = it->second;
	if (!modp->isTop()) {
	    string arrow = scopep->name();
	    string::size_type pos;
	    while ((pos=arrow.find(".")) != string::npos) {
		arrow.replace(pos, 1, "->");
	    }
	    if (arrow.substr(0,5) == "TOP->") arrow.replace(0,5,"TOPp->");
	    ofp()->printf("%-30s ", arrow.c_str());
	    puts(" = &");
	    puts(scopep->nameDotless()+";\n");
	}
    }

    puts("// Setup each module's pointer back to symbol table (for public functions)\n");
    puts("TOPp->__Vconfigure(this, true);\n");
    for (vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
	AstScope* scopep = it->first;  AstNodeModule* modp = it->second;
	if (!modp->isTop()) {
	    // first is used by AstCoverDecl's call to __vlCoverInsert
	    bool first = !modp->user1();
	    modp->user1(true);
	    puts(scopep->nameDotless()+".__Vconfigure(this, "
		 +(first?"true":"false")
		 +");\n");
	}
    }

    puts("// Setup scope names\n");
    for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
	puts("__Vscope_"+it->second.m_symName+".configure(this,name(),");
	putsQuoted(it->second.m_prettyName);
	puts(");\n");
    }

    if (v3Global.dpi()) {
	puts("// Setup export functions\n");
	puts("for (int __Vfinal=0; __Vfinal<2; __Vfinal++) {\n");
	for (ScopeFuncs::iterator it = m_scopeFuncs.begin(); it != m_scopeFuncs.end(); ++it) {
	    AstScopeName* scopep = it->second.m_scopep;
	    AstCFunc* funcp = it->second.m_funcp;
	    AstNodeModule* modp = it->second.m_modp;
	    if (funcp->dpiExport()) {
		puts("__Vscope_"+scopep->scopeSymName()+".exportInsert(__Vfinal,");
		putsQuoted(funcp->cname());
		puts(", (void*)(&");
		puts(modClassName(modp));
		puts("::");
		puts(funcp->name());
		puts("));\n");
	    }
	}
	// It would be less code if each module inserted its own variables.
	// Someday.  For now public isn't common.
	for (ScopeVars::iterator it = m_scopeVars.begin(); it != m_scopeVars.end(); ++it) {
	    AstNodeModule* modp = it->second.m_modp;
	    AstScope* scopep = it->second.m_scopep;
	    AstVar* varp = it->second.m_varp;
	    //
	    int pdim=0;
	    int udim=0;
	    string bounds;
	    if (AstBasicDType* basicp = varp->basicp()) {
		// Range is always first, it's not in "C" order
		if (basicp->isRanged()) {
		    bounds += " ,"; bounds += cvtToStr(basicp->msb());
		    bounds += ","; bounds += cvtToStr(basicp->lsb());
		    pdim++;
		}
		for (AstNodeDType* dtypep=varp->dtypep(); dtypep; ) {
		    dtypep = dtypep->skipRefp();  // Skip AstRefDType/AstTypedef, or return same node
		    if (AstNodeArrayDType* adtypep = dtypep->castNodeArrayDType()) {
			bounds += " ,"; bounds += cvtToStr(adtypep->msb());
			bounds += ","; bounds += cvtToStr(adtypep->lsb());
			if (dtypep->castPackArrayDType()) pdim++; else udim++;
			dtypep = adtypep->subDTypep();
		    }
		    else break; // AstBasicDType - nothing below, 1
		}
	    }
	    //
	    if (pdim>1 || udim>1) {
		puts("//UNSUP ");  // VerilatedImp can't deal with >2d or packed arrays
	    }
	    puts("__Vscope_"+it->second.m_scopeName+".varInsert(__Vfinal,");
	    putsQuoted(it->second.m_varBasePretty);
	    puts(", &(");
	    if (modp->isTop()) {
		puts(scopep->nameDotless());
		puts("p->");
	    } else {
		puts(scopep->nameDotless());
		puts(".");
	    }
	    puts(varp->name());
	    puts("), ");
	    puts(varp->vlEnumType());  // VLVT_UINT32 etc
	    puts(",");
	    puts(varp->vlEnumDir());  // VLVD_IN etc
	    if (varp->isSigUserRWPublic()) puts("|VLVF_PUB_RW");
	    else if (varp->isSigUserRdPublic()) puts("|VLVF_PUB_RD");
	    puts(",");
	    puts(cvtToStr(pdim+udim));
	    puts(bounds);
	    puts(");\n");
	}
	puts("}\n");
    }

    puts("}\n");

    if (v3Global.opt.savable() ) {
	puts("\n");
	for (int de=0; de<2; ++de) {
	    string classname = de ? "VerilatedDeserialize" : "VerilatedSerialize";
	    string funcname = de ? "__Vdeserialize" : "__Vserialize";
	    string op = de ? ">>" : "<<";
	    puts("void "+symClassName()+"::"+funcname+"("+classname+"& os) {\n");
	    puts(   "// LOCAL STATE\n");
	    // __Vm_namep presumably already correct
	    puts(   "os"+op+"__Vm_activity;\n");
	    puts(   "os"+op+"__Vm_didInit;\n");
	    puts(   "// SUBCELL STATE\n");
	    for (vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
		AstScope* scopep = it->first;  AstNodeModule* modp = it->second;
		if (!modp->isTop()) {
		    puts(   scopep->nameDotless()+"."+funcname+"(os);\n");
		}
	    }
	    puts("}\n");
	}
    }
}