diff --git a/Changes b/Changes index 80c5abcc5..a975d2e6e 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,8 @@ indicates the contributor was also the author of the fix; Thanks! * Verilator 3.61* +*** Support simple inout task ports. [Eugene Weber] + *** Allow overriding Perl, Flex and Bison versions. [by Robert Farrell] **** Default make no longer makes the docs; if you edit the documentation diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 9db071eae..12dbcc7db 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -85,7 +85,7 @@ int AstVar::widthTotalBytes() const { } string AstVar::verilogKwd() const { - if (isTristate()) { + if (isInout()) { return "inout"; } else if (isInput()) { return "input"; @@ -93,6 +93,8 @@ string AstVar::verilogKwd() const { return "output"; } else if (isInteger()) { return "integer"; + } else if (isTristate()) { + return "tri"; } else if (varType()==AstVarType::WIRE) { return "wire"; } else { @@ -325,9 +327,12 @@ void AstVarRef::dump(ostream& str) { void AstVar::dump(ostream& str) { this->AstNode::dump(str); if (isSc()) str<<" [SC]"; - if (isInput()) str<<" [I]"; - if (isPrimaryIO()) str<<(isInput()?" [PI]":" [PO]"); - if (isOutput()) str<<" [O]"; + if (isPrimaryIO()) str<<(isInout()?" [PIO]":(isInput()?" [PI]":" [PO]")); + else { + if (isInout()) str<<" [IO]"; + else if (isInput()) str<<" [I]"; + else if (isOutput()) str<<" [O]"; + } if (isUsedClock()) str<<" [C]"; if (isSigPublic()) str<<" [P]"; if (attrClockEn()) str<<" [aCLKEN]"; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 1faa85042..ff3213dc5 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -314,10 +314,13 @@ public: void name(const string& name) { m_name = name; } bool isInput() const { return m_input; } bool isOutput() const { return m_output; } - bool isTristate() const { return (m_tristate); } + bool isInOnly() const { return m_input && !m_output; } + bool isOutOnly() const { return m_output && !m_input; } + bool isInout() const { return m_input && m_output; } + bool isTristate() const { return m_tristate; } bool isPrimaryIO() const { return m_primaryIO; } bool isPrimaryIn() const { return isPrimaryIO() && isInput(); } - bool isIO() const { return (m_input||m_output||m_tristate); } + bool isIO() const { return (m_input||m_output); } bool isSignal() const { return (varType()==AstVarType::WIRE || varType()==AstVarType::IMPLICIT || varType()==AstVarType::REG || varType()==AstVarType::INTEGER); } bool isTemp() const { return (varType()==AstVarType::BLOCKTEMP || varType()==AstVarType::MODULETEMP diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 3afc585c7..207df58a8 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -702,7 +702,7 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) { if (nodep->attrScClocked() && nodep->isInput()) { puts("sc_in_clk\t"); } else { - if (nodep->isTristate()) puts("sc_inout<"); + if (nodep->isInout()) puts("sc_inout<"); else if (nodep->isInput()) puts("sc_in<"); else if (nodep->isOutput()) puts("sc_out<"); else nodep->v3fatalSrc("Unknown type"); @@ -714,7 +714,7 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) { puts(";\n"); } else { // C++ signals ofp()->putAlign(nodep->isStatic(), nodep->widthAlignBytes()); - if (nodep->isTristate()) puts("VL_INOUT"); + if (nodep->isInout()) puts("VL_INOUT"); else if (nodep->isInput()) puts("VL_IN"); else if (nodep->isOutput()) puts("VL_OUT"); else nodep->v3fatalSrc("Unknown type"); diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index 3eca5babb..99d466807 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -79,7 +79,7 @@ private: // or ASSIGNW(expr,VARXREF(p)) (if sub's output) UINFO(4," PIN "<=9) nodep->dumpTree(cout," Pin_oldb: "); - if (nodep->modVarp()->isOutput() && nodep->exprp()->castConst()) + if (nodep->modVarp()->isOutOnly() && nodep->exprp()->castConst()) nodep->v3error("Output pin is assigned to a constant, electrical short"); // Use userp on the PIN to indicate we created an assign for this pin if (!nodep->user()) { @@ -90,7 +90,9 @@ private: AstNode* exprp = nodep->exprp()->cloneTree(false); if (nodep->width() != nodep->modVarp()->width()) nodep->v3fatalSrc("Width mismatch, should have been handled in pinReconnectSimple\n"); - if (nodep->modVarp()->isOutput()) { + if (nodep->modVarp()->isInout()) { + nodep->v3fatalSrc("Unsupported: Verilator is a 2-state simulator"); + } else if (nodep->modVarp()->isOutput()) { AstNode* rhsp = new AstVarXRef (exprp->fileline(), nodep->modVarp(), m_cellp->name(), false); rhsp->widthSignedFrom(nodep); AstAssignW* assp = new AstAssignW (exprp->fileline(), exprp, rhsp); @@ -236,12 +238,14 @@ void V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstModule* modp) { } else { // Make a new temp wire //if (1||debug()>=9) { pinp->dumpTree(cout,"in_pin:"); } - AstAssignW* assignp; + 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->isOutput()) { + 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()) { @@ -265,7 +269,7 @@ void V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstModule* modp) { pinp->exprp(new AstVarRef (pinexprp->fileline(), newvarp, false)); } pinp->widthSignedFrom(pinp->exprp()); - modp->addStmtp(assignp); + if (assignp) modp->addStmtp(assignp); //if (1||debug()) { pinp->dumpTree(cout," out:"); } //if (1||debug()) { assignp->dumpTree(cout," aout:"); } } diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index 3e884d90d..7ff4f08d2 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -140,7 +140,7 @@ void V3LinkLevel::wrapTop(AstNetlist* netlistp) { AstVar* varp = oldvarp->cloneTree(false)->castVar(); newmodp->addStmtp(varp); varp->sigPublic(true); // User needs to be able to get to it... - if (oldvarp->isInput() || oldvarp->isOutput()) { + if (oldvarp->isIO()) { oldvarp->primaryIO(true); varp->primaryIO(true); } diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 77d4ee0e1..642fadcb9 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -111,7 +111,7 @@ private: // VarRef: Resolve its reference if (nodep->varp()) { nodep->varp()->usedParam(true); - if (nodep->lvalue() && nodep->varp()->isInput()) { + if (nodep->lvalue() && nodep->varp()->isInOnly()) { nodep->v3error("Assigning to input variable: "<prettyName()); } } diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 1d79f4d21..3314545f3 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -227,8 +227,14 @@ private: nextpinp = pinp->nextp(); pinp->unlinkFrBack(); // Relinked to assignment below // - if (portp->isTristate()) { - refp->v3error("Unsupported: Inouts in functions/tasks"); + if (portp->isInout()) { + if (AstVarRef* varrefp = pinp->castVarRef()) { + // Connect to this exact variable + AstVarScope* localVscp = varrefp->varScopep(); if (!localVscp) varrefp->v3fatalSrc("Null var scope"); + portp->user2p(localVscp); + } else { + pinp->v3error("Unsupported: Function/task input argument is not simple variable"); + } } else if (portp->isOutput() && outvscp) { refp->v3error("Outputs not allowed in function declarations"); diff --git a/test_regress/t/t_func.v b/test_regress/t/t_func.v index 9037ec5ae..60e4e01be 100644 --- a/test_regress/t/t_func.v +++ b/test_regress/t/t_func.v @@ -1,4 +1,4 @@ -// $Id:$ +// $Id$ // DESCRIPTION: Verilator: Verilog Test module // // This file ONLY is placed into the Public Domain, for any use, @@ -22,6 +22,12 @@ module t; if (global != 32'h17) $stop; nop(32'h11); + global = 32'h00000001; + flipbit(global,5'd8); + flipbit(global,5'd16); + flipbit(global,5'd24); + if (global !== 32'h01010101) $stop; + $write("*-* All Finished *-*\n"); $finish; end @@ -70,4 +76,10 @@ module t; end endtask + task flipbit; + inout [31:0] vector; + input [4:0] bitnum; + vector[bitnum] = vector[bitnum] ^ 1'b1; + endtask + endmodule