Beispiel #1
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);
    }
Beispiel #2
0
    void varsExpand() {
	// We didn'e have all m_scopes loaded when we encountered variables, so expand them now
	// It would be less code if each module inserted its own variables.
	// Someday.  For now public isn't common.
	for (vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
	    AstScope* scopep = it->first;  AstNodeModule* smodp = it->second;
	    for (vector<ModVarPair>::iterator it = m_modVars.begin(); it != m_modVars.end(); ++it) {
		AstNodeModule* modp = it->first;
		AstVar* varp = it->second;
		if (modp == smodp) {
		    // Need to split the module + var name into the original-ish full scope and variable name under that scope.
		    // The module instance name is included later, when we know the scopes this module is under
		    string whole = scopep->name()+"__DOT__"+varp->name();
		    string scpName;
		    string varBase;
		    if (whole.substr(0,10) == "__DOT__TOP") whole.replace(0,10,"");
		    string::size_type pos = whole.rfind("__DOT__");
		    if (pos != string::npos) {
			scpName = whole.substr(0,pos);
			varBase = whole.substr(pos+strlen("__DOT__"));
		    } else {
			varBase = whole;
		    }
		    //UINFO(9,"For "<<scopep->name()<<" - "<<varp->name()<<"  Scp "<<scpName<<"  Var "<<varBase<<endl);
		    string varBasePretty = AstNode::prettyName(varBase);
		    string scpPretty = AstNode::prettyName(scpName);
		    string scpSym;
		    {
			string out = scpName;
			string::size_type pos;
			while ((pos=out.find("__PVT__")) != string::npos) {
			    out.replace(pos, 7, "");
			}
			if (out.substr(0,10) == "TOP__DOT__") out.replace(0,10,"");
			if (out.substr(0,4) == "TOP.") out.replace(0,4,"");
			while ((pos=out.find(".")) != string::npos) {
			    out.replace(pos, 1, "__");
			}
			while ((pos=out.find("__DOT__")) != string::npos) {
			    out.replace(pos, 7, "__");
			}
			scpSym = out;
		    }
		    //UINFO(9," scnameins sp "<<scpName<<" sp "<<scpPretty<<" ss "<<scpSym<<endl);
		    if (m_scopeNames.find(scpSym) == m_scopeNames.end()) {
			m_scopeNames.insert(make_pair(scpSym, ScopeNameData(scpSym, scpPretty)));
		    }
		    m_scopeVars.insert(make_pair(scpSym + " " + varp->name(),
						 ScopeVarData(scpSym, varBasePretty, varp, modp, scopep)));
		}
	    }
	}
    }
Beispiel #3
0
    virtual void visit(AstVar* nodep, AstNUser*) {
	if (m_state == CONVERT_VARS) {
	    if (nodep->isTristate() && !m_ftaskp) {
		// create the input var and leave the original as the output var
		AstVar* varinp = nodep->cloneTree(false)->castVar();
		varinp->name(varinp->name() + "__in");
		varinp->varType2In();

		nodep->combineType(AstVarType::OUTPUT);
		nodep->varType2Out();
		m_modp->addStmtp(varinp);
		nodep->user1p(varinp);
	    }
	}
    }
Beispiel #4
0
void AstPrinterVisitor::visitBlockNode(BlockNode* node) {
    if (!isMainScope(node->scope())) {
        _output << "{" << endl;
    }

    Scope::VarIterator varIt(node->scope());
    while(varIt.hasNext()) {
        AstVar* var = varIt.next();
        printVarType(var->type());
        _output << " " << var->name();
        printSemicolon();
    }

    Scope::FunctionIterator funcIt(node->scope());
    while(funcIt.hasNext()) {
        FunctionNode* func = funcIt.next()->node();
        func->visit(this);
    }

    for (uint32_t i = 0; i < node->nodes(); ++i) {
        node->nodeAt(i)->visit(this);
        if (!(node->nodeAt(i)->isIfNode()
              || node->nodeAt(i)->isWhileNode()
              || node->nodeAt(i)->isForNode()
              || node->nodeAt(i)->isReturnNode()
              || node->nodeAt(i)->isBlockNode())) {
            printSemicolon();
        }
    }
    if (!isMainScope(node->scope())) {
        _output << "}" << endl;
    }
}
Beispiel #5
0
    AstVarScope* getCreateLastClk(AstVarScope* vscp) {
	if (vscp->user1p()) return ((AstVarScope*)vscp->user1p());
	AstVar* varp = vscp->varp();
	if (!varp->width1()) varp->v3error("Unsupported: Clock edge on non-single bit signal: "<<varp->prettyName());
	string newvarname = ((string)"__Vclklast__"+vscp->scopep()->nameDotless()+"__"+varp->name());
        AstVar* newvarp = new AstVar(vscp->fileline(), AstVarType::MODULETEMP, newvarname, VFlagLogicPacked(), 1);
        newvarp->noReset(true);  // Reset by below assign
	m_modp->addStmtp(newvarp);
	AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopep, newvarp);
	vscp->user1p(newvscp);
	m_scopep->addVarp(newvscp);
        // Add init
        AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, false);
        if (v3Global.opt.xInitialEdge()) fromp = new AstNot(fromp->fileline(), fromp);
        AstNode* newinitp = new AstAssign(vscp->fileline(),
                                          new AstVarRef(newvarp->fileline(), newvscp, true),
                                          fromp);
        addToInitial(newinitp);
	// At bottom, assign them
	AstAssign* finalp
            = new AstAssign(vscp->fileline(),
                            new AstVarRef(vscp->fileline(), newvscp, true),
                            new AstVarRef(vscp->fileline(), vscp, false));
	m_evalFuncp->addFinalsp(finalp);
	//
	UINFO(4,"New Last: "<<newvscp<<endl);
	return newvscp;
    }
Beispiel #6
0
    virtual void visit(AstVarScope* nodep, AstNUser*) {
	nodep->iterateChildren(*this);
	// Avoid updating this if (), instead see varp->isTrace()
	if (!nodep->varp()->isTemp() && !nodep->varp()->isFuncLocal()) {
	    UINFO(5, "    vsc "<<nodep<<endl);
	    AstVar* varp = nodep->varp();
	    AstScope* scopep = nodep->scopep();
	    // Compute show name
	    // This code assumes SPTRACEVCDC_VERSION >= 1330;
	    // it uses spaces to separate hierarchy components.
	    m_traShowname = AstNode::vcdName(scopep->name() + " " + varp->name());
	    if (m_traShowname.substr(0,4) == "TOP ") m_traShowname.replace(0,4,"");
	    if (!m_initSubFuncp) nodep->v3fatalSrc("NULL");

	    m_traVscp = nodep;
	    m_traValuep = NULL;
	    if (varIgnoreTrace(varp)) {
		addIgnore(varIgnoreTrace(varp));
	    } else {
		++m_statSigs;
		if (nodep->valuep()) m_traValuep = nodep->valuep()->cloneTree(true);
		else m_traValuep = new AstVarRef(nodep->fileline(), nodep, false);
		{
		    // Recurse into data type of the signal; the visitors will call addTraceDecl()
		    varp->dtypeSkipRefp()->accept(*this);
		}
		// Cleanup
		if (m_traValuep) { m_traValuep->deleteTree(); m_traValuep=NULL; }
	    }
	    m_traVscp = NULL;
	    m_traValuep = NULL;
	    m_traShowname = "";
	}
    }
Beispiel #7
0
void Printer::printBlockContents(BlockNode* node) {
    // functions delcarations
    Scope::FunctionIterator funIt(node->scope());
    while (funIt.hasNext()) {
        funIt.next()->node()->visit(this);
        out << '\n';
    }

	// variables declarations
    Scope::VarIterator varIt(node->scope());
    while (varIt.hasNext()) {
        AstVar* var = varIt.next();
        out << typeToName(var->type()) 
        	<< " " << var->name() << ";\n";
    }

    // nodes
    for (size_t i = 0; i < node->nodes(); ++i) {
        AstNode* subNode = node->nodeAt(i);
        subNode->visit(this);
        if (!subNode->isIfNode() && 
        	!subNode->isWhileNode() && 
        	!subNode->isForNode()) {
            out << ';';
        }
        out << '\n';
    }
}
 void drivenBit (int bit, int width) {
     UINFO(9, "set d["<<(bit+width-1)<<":"<<bit<<"] "<<m_varp->name()<<endl);
     for (int i=0; i<width; i++) {
         if (bitNumOk(bit+i)) {
             m_flags[(bit+i)*FLAGS_PER_BIT + FLAG_DRIVEN] = true;
         }
     }
 }
Beispiel #9
0
 void printVars(Scope *scope)
 {
     Scope::VarIterator iter(scope);
     while (iter.hasNext()) {
         AstVar *astVar = iter.next();
         out << typeToName(astVar->type()) << " " << astVar->name() << ";" << endl;
     }
 }
Beispiel #10
0
 void variableDeclaration(Scope* scope) {
   Scope::VarIterator iter(scope);
   while (iter.hasNext()) {
     AstVar* x = iter.next();
     indent();
     _output << typeToName(x->type()) << " "
             << x->name() << ";"
             << endl;
   }
 }
ScopeHandler::ScopeHandler(uint16_t iniLocalId, Scope *scope, ScopeHandler *parent)
    : m_scope(scope)
    , m_parent(parent)
{
    Scope::VarIterator it = Scope::VarIterator(m_scope);
    while(it.hasNext()) {
        AstVar *var = it.next();
        m_varNameToId[var->name()] = iniLocalId;
        iniLocalId++;
    }
}
Beispiel #12
0
void ASTAnalyzer::printScopeDeclarations (Scope* scope) {
    Scope::FunctionIterator fuctions(scope);
    while (fuctions.hasNext()) {
        fuctions.next()->node()->visit(this);
    }
    Scope::VarIterator vars(scope);
    while (vars.hasNext()) {
        AstVar* var = vars.next();
        output << typeToName(var->type()) << " " << var->name() << ";\n";
    }
}
Beispiel #13
0
// private:
// visitBlockNodeImpl
void BytecodeGenerator::visitVarDecls(BlockNode* node) {
    Bytecode* bc = _state.currentBcToFill();
    Scope::VarIterator varIt(node->scope());
    while(varIt.hasNext()) {
        AstVar* var = varIt.next();
        uint16_t varId = _state.currentCtxAddVar(var->name(), node->position());
        Instruction bcLoad0 = typedInsn(var->type(), BC_ILOAD0, BC_DLOAD0, BC_SLOAD0);
        bc->addInsn(bcLoad0);
        Instruction bcStore = typedInsn(var->type(), BC_STOREIVAR, BC_STOREDVAR, BC_STORESVAR);
        genBcInsnWithId(bc, bcStore, varId);
    }
}
Beispiel #14
0
        void visitScope(Scope * scope) {
            Scope::VarIterator varIter(scope);
            while (varIter.hasNext()) {
                addIndent();
                AstVar * var = varIter.next();
                out<< typeToName(var->type())<< " "<< var->name()<< ";"<< endl;

            }
            Scope::FunctionIterator funcIter(scope);
            while (funcIter.hasNext()) {

                funcIter.next()->node()->visit(this);
            }
        }
Beispiel #15
0
void Ast2SrcVisitor::initScope(Scope* scope) {
    std::string indent(_indent, ' ');

    Scope::VarIterator varIt(scope);
    while (varIt.hasNext()) {
        AstVar* var = varIt.next();
        _out << indent << mathvm::typeToName(var->type()) << " "<< var->name() << ";" << std::endl;
    }

    Scope::FunctionIterator funcIt(scope);
    while (funcIt.hasNext()) {
        funcIt.next()->node()->visit(this);
        _out << std::endl;
    }
}
Beispiel #16
0
void PrettyPrinter::printScope(Scope *scope)
{
	std::string indentation(m_indent, ' ');
	//why constructor doesn't get const pointer?
	Scope::VarIterator ivar(scope);
	//Java-style iterators in C++?
	while (ivar.hasNext())
	{
		AstVar *var = ivar.next();
		m_out << indentation << typeToName(var->type()) << " "
		      << var->name() << ";" << std::endl;
	}
	
	Scope::FunctionIterator ifun(scope);
	while (ifun.hasNext()) ifun.next()->node()->visit(this);
}
Beispiel #17
0
void AstPrinter::printScopeDeclarations(Scope* scope) {
    Scope::VarIterator varIterator(scope);
    while(varIterator.hasNext()) {
        AstVar *var = varIterator.next();
        print(typeToName(var->type()));
        print(" ");
        print(var->name());
        print(";\n");
    }
    
    Scope::FunctionIterator funcIterator(scope);
    while(funcIterator.hasNext()) {
        AstFunction *func = funcIterator.next();
		printFunction(func);
    }
    print("\n");
}
Beispiel #18
0
    void printScope(Scope * scope) {
        Scope::VarIterator varIt(scope); 

        while(varIt.hasNext()) {
            AstVar* var = varIt.next();

            os << indent();
            os << typeToName(var->type()) << " " << var->name() << ";" << endl;
        }

        Scope::FunctionIterator funcIt(scope);
        while(funcIt.hasNext()) {
            AstFunction* func = funcIt.next();
            
            os << indent();
            func->node()->visit(this);
        }
    }
    void BytecodeVisitor::visitBlockNode(BlockNode *node) {
        LOG_Visitor("visitBlockNode");

        Scope::VarIterator variableIterator(node->scope());
        while (variableIterator.hasNext()) {
            AstVar *var = variableIterator.next();
            context->introduceVariable(var->type(), var->name());
        }
        Scope::FunctionIterator functionIterator(node->scope());
        while (functionIterator.hasNext()) {
            context->introduceFunction(new BytecodeFunction(functionIterator.next()));
        }

        node->visitChildren(this);

        functionIterator = Scope::FunctionIterator(node->scope());
        while (functionIterator.hasNext()) {
            visitFunctionNode(functionIterator.next()->node());
        }
    }
Beispiel #20
0
void ByteCodeVisitor::initVars(Scope *scope) {
    if (!scope) return;
    Scope::VarIterator varIt(scope);
    while (varIt.hasNext()) {
        AstVar *var = varIt.next();
        if (!var->info()) {
            var->setInfo(new AstVarInfo(currentBytecodeFunction->id(), currentBytecodeFunction->localsNumber()));
            currentBytecodeFunction->setLocalsNumber(currentBytecodeFunction->localsNumber() + 1);
            if (currentBytecodeFunction->localsNumber() >= UINT16_MAX) {
                error("vars overflow in function <%s,id>", currentBytecodeFunction->name().c_str(), currentBytecodeFunction->id());
            }
        } else {
            AstVarInfo *varInfo = (AstVarInfo *) var->info();
            TranslatedFunction *function = interpreterCode->functionById(varInfo->contextId);
            error("variable already declared var <%s,%d,%d> for function %s",
                    var->name().c_str(), varInfo->contextId, varInfo->id, function->name().c_str());
        }
    }

}
void SourceByASTPrinter::visitBlockNodeWithoutBraces(BlockNode *node){
	Scope::VarIterator vIt(node->scope());
	while(vIt.hasNext()) {
		AstVar *var = vIt.next();
		cout<<typeToName(var->type())<<" "<< var->name()<< ";"<<endl;
	}

	Scope::FunctionIterator fIt(node->scope());
	while(fIt.hasNext()) {
		fIt.next()->node()->visit(this);
	}

	int nodesNumber = node->nodes();
	for (int i = 0; i < nodesNumber; ++i) {
		AstNode *nodeAt = node->nodeAt(i);
		nodeAt->visit(this);
		if(!nodeAt->isForNode() && !nodeAt->isIfNode() && !nodeAt->isWhileNode())
			cout<<";"<<endl;
	}
}
Beispiel #22
0
    // METHODS
    AstVarScope* genInpClk(AstVarScope* vscp) {
	if (vscp->user2p()) {
            return VN_CAST(vscp->user2p(), VarScope);
	} else {
	    AstVar* varp = vscp->varp();
	    string newvarname = "__VinpClk__"+vscp->scopep()->nameDotless()+"__"+varp->name();
	    // Create:  VARREF(inpclk)
	    //          ...
	    //          ASSIGN(VARREF(inpclk), 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);
            AstAssign* asninitp = new AstAssign(vscp->fileline(),
                                                new AstVarRef(vscp->fileline(), newvscp, true),
                                                new AstVarRef(vscp->fileline(), vscp, false));
	    m_scopetopp->addFinalClkp(asninitp);
	    //
	    vscp->user2p(newvscp);
	    return newvscp;
	}
    }
Beispiel #23
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");
	}
    }
}
 void drivenWhole() {
     UINFO(9, "set d[*] "<<m_varp->name()<<endl);
     m_drivenWhole = true;
 }
 void usedWhole() {
     UINFO(9, "set u[*] "<<m_varp->name()<<endl);
     m_usedWhole = true;
 }
    bool forUnrollCheck(AstNode* nodep,
			AstNode* initp,	// Maybe under nodep (no nextp), or standalone (ignore nextp)
			AstNode* precondsp, AstNode* condp,
			AstNode* incp,		// Maybe under nodep or in bodysp
			AstNode* bodysp) {
	// To keep the IF levels low, we return as each test fails.
	UINFO(4, " FOR Check "<<nodep<<endl);
	if (initp)	UINFO(6, "    Init "<<initp<<endl);
	if (precondsp)	UINFO(6, "    Pcon "<<precondsp<<endl);
	if (condp)	UINFO(6, "    Cond "<<condp<<endl);
	if (incp)	UINFO(6, "    Inc  "<<incp<<endl);
	// Initial value check
	AstAssign* initAssp = initp->castAssign();
	if (!initAssp) return cantUnroll(nodep, "no initial assignment");
	if (initp->nextp() && initp->nextp()!=nodep) nodep->v3fatalSrc("initial assignment shouldn't be a list");
	if (!initAssp->lhsp()->castVarRef()) return cantUnroll(nodep, "no initial assignment to simple variable");
	m_forVarp = initAssp->lhsp()->castVarRef()->varp();
	m_forVscp = initAssp->lhsp()->castVarRef()->varScopep();
	if (nodep->castGenFor() && !m_forVarp->isGenVar()) {
	    nodep->v3error("Non-genvar used in generate for: "<<m_forVarp->name()<<endl);
	}
	if (m_generate) V3Const::constifyParamsEdit(initAssp->rhsp());  // rhsp may change
	AstConst* constInitp = initAssp->rhsp()->castConst();
	if (!constInitp) return cantUnroll(nodep, "non-constant initializer");
	//
	// Condition check
	if (condp->nextp()) nodep->v3fatalSrc("conditional shouldn't be a list");
	//
	// Assignment of next value check
	AstAssign* incAssp = incp->castAssign();
	if (!incAssp) return cantUnroll(nodep, "no increment assignment");
	if (incAssp->nextp()) nodep->v3fatalSrc("increment shouldn't be a list");
	AstNodeBiop* incInstrp = incAssp->rhsp()->castNodeBiop();
	//
	if (m_forVscp) { UINFO(8, "   Loop Variable: "<<m_forVscp<<endl); }
	else	       { UINFO(8, "   Loop Variable: "<<m_forVarp<<endl); }
	if (debug()>=9) nodep->dumpTree(cout,"-   for: ");
	//
	// Extract the constant loop bounds
	bool subtract = incInstrp->castSub();
	{
	    if (!subtract && !incInstrp->castAdd()) return cantUnroll(nodep, "missing add/sub for incrementer");
	    AstVarRef* incVarrp   = (subtract ? incInstrp->lhsp()->castVarRef()
				     : incInstrp->rhsp()->castVarRef());
	    if (!incVarrp) return cantUnroll(nodep, "missing variable in incrementer");
	    if (incVarrp->varp() != m_forVarp
		|| incVarrp->varScopep() != m_forVscp) {
		return cantUnroll(nodep, "different variables in incrementer");
	    }
	}
	//
	// Adds have the # on the lhsp because V3Const pushes rhs consts over to the lhs
	// Subtracts have it on the rhs, because you write i=i-1; i=1-i is non-sensible.
	AstConst* preconstIncp = (subtract ? incInstrp->rhsp()->castConst()
				  : incInstrp->lhsp()->castConst());
	if (m_generate) preconstIncp = V3Const::constifyParamsEdit(preconstIncp)->castConst();
	AstConst* constIncp = (subtract ? incInstrp->rhsp()->castConst()
			       : incInstrp->lhsp()->castConst());
	UINFO(8, "   Inc expr ok:  "<<constIncp<<endl);
	if (!constIncp) return cantUnroll(nodep, "non-constant increment");
	if (constIncp->isZero()) return cantUnroll(nodep, "zero increment");  // Or we could loop forever below...

        bool lt  = condp->castLt() || condp->castLtS();
        bool lte = condp->castLte() || condp->castLteS();
	bool gt  = condp->castGt() || condp->castGtS();
	bool gte = condp->castGte() || condp->castGteS();
	if (!lt && !lte && !gt && !gte)
	    return cantUnroll(nodep, "condition not <= or <");
	AstNodeBiop* condBip = condp->castNodeBiop();
	if (!condBip->lhsp()->castVarRef())
	    return cantUnroll(nodep, "no variable on lhs of condition");
	if (condBip->lhsp()->castVarRef()->varp() != m_forVarp
	    || condBip->lhsp()->castVarRef()->varScopep() != m_forVscp)
	    return cantUnroll(nodep, "different variable in condition");
	if (m_generate) V3Const::constifyParamsEdit(condBip->rhsp());  // rhsp may change
	AstConst* constStopp = condBip->rhsp()->castConst();
	if (!constStopp) return cantUnroll(nodep, "non-constant final value");
	UINFO(8, "   Stop expr ok: "<<constStopp<<endl);
	//
	if (constInitp->width()>32 || constInitp->num().isFourState()
	    || constStopp->width()>32 || constStopp->num().isFourState()
	    || constIncp->width()>32  || constIncp->num().isFourState())
	    return cantUnroll(nodep, "init/final/increment too large or four state");
	vlsint32_t valInit = constInitp->num().toSInt();
	vlsint32_t valStop = constStopp->num().toSInt();
	if (lte) valStop++;  if (gte) valStop--;
	vlsint32_t valInc  = constIncp->num().toSInt();
	if (subtract) valInc = -valInc;
	UINFO(8,"     In Numbers: for (v="<<valInit<<"; v<"<<valStop<<"; v=v+"<<valInc<<")\n");
	//
	if (!m_generate) {
	    int loops = ((valStop - valInit)/valInc);
	    if (loops < 0) { loops += (1ULL<<constStopp->width()); } // Will roll around
	    UINFO(8, "         ~Iters: "<<loops<<" c="<<unrollCount()<<endl);
	    if (loops > unrollCount())
		return cantUnroll(nodep, "too many iterations");

	    // Less than 10 statements in the body?
	    int bodySize = 0;
	    int bodyLimit = v3Global.opt.unrollStmts();
	    if (loops>0) bodyLimit = v3Global.opt.unrollStmts() / loops;
	    if (bodySizeOverRecurse(precondsp, bodySize/*ref*/, bodyLimit)
		|| bodySizeOverRecurse(bodysp, bodySize/*ref*/, bodyLimit)
		|| bodySizeOverRecurse(incp, bodySize/*ref*/, bodyLimit)) {
		return cantUnroll(nodep, "too many statements");
	    }
	}
	//
	// Now, make sure there's no assignment to this variable in the loop
	m_varModeCheck = true;
	m_varAssignHit = false;
	m_ignoreIncp = incp;
	precondsp->iterateAndNext(*this);
	bodysp->iterateAndNext(*this);
	incp->iterateAndNext(*this);
	m_varModeCheck = false;
	m_ignoreIncp = NULL;
	if (m_varAssignHit) return cantUnroll(nodep, "genvar assigned *inside* loop");
	//
	// Finally, we can do it
	forUnroller(nodep, initp, precondsp, condp, incp, bodysp,
		    constInitp->num(),
		    condBip, constStopp->num(),
		    incInstrp, constIncp->num()); nodep = NULL;
	// Cleanup
	return true;
    }
Beispiel #27
0
    virtual void visit(AstNodeModule* nodep, AstNUser*) {
	UINFO(9," MOD   "<<nodep<<endl);
	m_unique = 0;
	VarMap* lhsmapp = new VarMap();

	// expand tristate nodes and detect multiple LHS drivers for this module
	TristateExpander(nodep, lhsmapp);

	// iterate the children to grab any  __en signals from subcells
	m_modp = nodep;
	nodep->iterateChildren(*this);
	m_modp = NULL;

	// go through each multiple lhs driver & collapse it to a single driver
	for (VarMap::iterator nextit, it=lhsmapp->begin(); it != lhsmapp->end(); it=nextit) {
	    nextit = it; ++nextit;
	    m_unique = 0;
	    AstVar* lhsp = (*it).first;
	    RefVec* refs = (*it).second;
	    bool isOutput = (lhsp->varType() == AstVarType::OUTPUT) && (nodep->level() > 1); // force termination at top level

	    if (refs->size() < 2 && isOutput) {
		// if only one driver and this is an output, then exit and
		// let the driver propagate on its own.  If the signals
		// terminates at this level, then we need to let the
		// undriven state get generated.
		lhsmapp->erase(lhsp);
		delete refs;
		continue;
	    }


	    UINFO(9, "       Checking " << refs->size() << " drivers for tristates signals on net " << lhsp << endl);
	    int pull = 0;  // initially assume no pull direction

	    // Now remove and multple lhs signals that do not have __en for
	    // all possible drivers.
	    bool complete = true;
	    int found_one = 0;

	    for (RefVec::iterator ii=refs->begin(); ii != refs->end(); ++ii) {
		AstVarRef* refp = (*ii);
		if (!refp->user1p()) { // if no __en signal, then delete the entry
		    complete = false;
		} else {
		    found_one++;
		}
	    }
	    if (!complete) {
		if (found_one) {
		    UINFO(9, "       Problem mixing tristate and low-Z on " << lhsp << endl);
		    UINFO(9, "       Found " << found_one << " __en signals from of " << refs->size() << " possible drivers" << endl);
		    // not sure what I should do here other than error that they are mixing low-Z and tristate drivers.
		    // The other scenerio, and probably more likely, is that they are using a high-Z construct that
		    // is not supported.  Improving the high-Z detection logic will reduce the occurance of this failure.
		    nodep->v3error("Mixing tristate and low-Z drivers.  Perhaps you are using a high-Z construct not supported");
		} else  {
		    UINFO(9, "       No tristates found on " << lhsp <<endl);
		}
		lhsmapp->erase(lhsp);
		delete refs;
		continue;
	    }

	    UINFO(9, "       TRISTATE LHS DRIVER FOUND:" << lhsp << endl);

	    AstNode* orp = NULL,* andp = NULL,* undrivenp = NULL,* newenlogicp = NULL;

	    // loop through the lhs drivers to build the driver resolution logic
	    for (RefVec::iterator ii=refs->begin(); ii != refs->end(); ++ii) {
		AstVarRef* refp = (*ii);
		int w = lhsp->width();
		int wfill = 0; // width filler when necessary due to sels
		AstSel* selp = NULL;
		if (refp->user3p()) { // this varref has a sel
		    selp = (AstSel*) refp->user3p();
		    w = selp->widthConst();
		    wfill = lhsp->width() - w;
		}

		// create a new var for this assignment.
		AstVar* enp = (AstVar*)refp->user1p();
		AstVar* newlhsp = new AstVar(lhsp->fileline(),
					     AstVarType::MODULETEMP,
					     lhsp->name()+"__lhs"+cvtToStr(m_unique++),
					     AstLogicPacked(), w);
		nodep->addStmtp(newlhsp);

		// now append this driver to the driver logic.
		AstNode* ref1 = new AstVarRef(nodep->fileline(), newlhsp,false);
		AstNode* ref2 = new AstVarRef(nodep->fileline(), enp, false);
		andp = new AstAnd(nodep->fileline(), ref1, ref2);


		AstVar* bitselp = NULL;
		if (selp) { // this varref has a sel
		    int ws = V3Number::log2b(lhsp->width())+1;
		    bitselp = new AstVar(lhsp->fileline(),
					 AstVarType::MODULETEMP,
					 lhsp->name()+"__sel"+cvtToStr(m_unique-1),
					 AstLogicPacked(), ws);
		    //
		    nodep->addStmtp(bitselp);
		    nodep->addStmtp(new AstAssignW(lhsp->fileline(),
						   new AstVarRef(lhsp->fileline(), bitselp, true),
						   selp->lsbp()->cloneTree(false)));
		    andp = new AstShiftL(lhsp->fileline(),
					 new AstConcat(lhsp->fileline(), new AstConst(lhsp->fileline(), V3Number(lhsp->fileline(), wfill, 0)), andp),
					 new AstVarRef(lhsp->fileline(), bitselp, false),
					 lhsp->width()
			);

		    selp->replaceWith(new AstVarRef(refp->fileline(), newlhsp, true));
		    pushDeletep(selp);  // Setting selp here or deleting immediately
		    // breaks the t_tri_select test, this probably indicates a problem
		} else {
		    refp->varp(newlhsp); // assign the new var to the varref
		    refp->name(newlhsp->name());
		}

		// or this to the others
		orp = (!orp) ? andp : new AstOr(nodep->fileline(), orp, andp);

		if (isOutput) {
		    AstNode *en1p = new AstVarRef(nodep->fileline(), enp, false);
		    if (selp) {
			en1p = new AstShiftL(enp->fileline(),
					     new AstConcat(lhsp->fileline(), new AstConst(lhsp->fileline(), V3Number(lhsp->fileline(), wfill, 0)), en1p),
					     new AstVarRef(lhsp->fileline(), bitselp, false),
					     lhsp->width()
			    );
		    }
		    if (!newenlogicp) {
			newenlogicp = en1p;
		    } else {
			newenlogicp = new AstOr(nodep->fileline(), newenlogicp, en1p);
		    }
		} else {
		    if (!undrivenp) {
			undrivenp = new AstNot(nodep->fileline(), new AstVarRef(nodep->fileline(), enp, false));
			if (selp)
			    undrivenp = new AstShiftL(enp->fileline(),
						      new AstConcat(lhsp->fileline(), new AstConst(lhsp->fileline(), V3Number(lhsp->fileline(), wfill, 0)), undrivenp),
						      new AstVarRef(lhsp->fileline(), bitselp, false),
						      lhsp->width());
		    } else {
			AstNode *tmp = new AstNot(nodep->fileline(), new AstVarRef(nodep->fileline(), enp, false));
			if (selp) {
			    tmp = new AstShiftL(enp->fileline(),
						new AstConcat(lhsp->fileline(), new AstConst(lhsp->fileline(), V3Number(lhsp->fileline(), wfill, 0)), tmp),
						new AstVarRef(lhsp->fileline(), bitselp, false),
						lhsp->width());
			}
			undrivenp = new AstAnd(nodep->fileline(), tmp, undrivenp);
		    }
		}

		refp->user1p(NULL); // clear the user1p() as we done with it in the VarRef at this point

		if (enp->user2()) { // if this net is pulled up/down
		    int newpull = enp->user2();
		    if (pull == 0) {
			pull = newpull;
		    } else if (newpull != pull) {
			pull = -1; // conflict over the pull direction
		    }
		}
	    }
	    if (isOutput) {
		AstVar* newenp = new AstVar(lhsp->fileline(),
					    AstVarType::OUTPUT,
					    lhsp->name()+"__enout"+cvtToStr(m_unique++),
					    lhsp);
		nodep->addStmtp(newenp);
		nodep->addStmtp(new AstAssignW(lhsp->fileline(),
					       new AstVarRef(lhsp->fileline(), newenp, true),
					       newenlogicp));
		newenp->user2(pull); // put the pull direction in the next __en signal to pass it up
		lhsp->user1p(newenp); // put the new __en signal in the var so it can be pushed up the hierarchy.

	    } else { // this is the level where the signal terminates, we do final conflict resolution here
		UINFO(9, "       Terminating tristate logic for " << lhsp->name() << endl);
		UINFO(9, "       Pull direction is " << pull << " where -1=X, 0=Z, 1=low, 2=high." << endl);
		// figure out what to drive when no one is driving the bus
		V3Number num(nodep->fileline(), lhsp->width());
		if (pull==0) {
		    num.setAllBitsZ();
		} else if (pull==1) {
		    num.setAllBits0();
		} else if (pull==2) {
		    num.setAllBits1();
		} else {
		    num.setAllBitsX();
		}
		undrivenp = new AstAnd(nodep->fileline(), undrivenp,
				       new AstConst(nodep->fileline(), num));
		orp = new AstOr(nodep->fileline(), orp, undrivenp);
	    }
	    nodep->addStmtp(new AstAssignW(lhsp->fileline(),
					   new AstVarRef(lhsp->fileline(), lhsp, true), orp));

	    // delete the map and vector list now that we have collapsed it.
	    lhsmapp->erase(lhsp);
	    delete refs;
	}
	delete lhsmapp; // delete the map now that we are done
	nodep->user1p(NULL);
    }