diff --git a/Changes b/Changes index a6b1caa10..e50cadfb8 100644 --- a/Changes +++ b/Changes @@ -3,6 +3,11 @@ Revision history for Verilator The contributors that suggested a given feature are shown in []. [by ...] indicates the contributor was also the author of the fix; Thanks! +* Verilator 3.7** + +*** Support byte, shortint, int, longint in variables, parameters and + functions. + * Verilator 3.720 2009/10/26 ** Support little endian bit vectors ("reg [0:2] x;"). diff --git a/bin/verilator b/bin/verilator index dbea87bae..265240e99 100755 --- a/bin/verilator +++ b/bin/verilator @@ -1700,13 +1700,13 @@ This section describes specific limitations for each language keyword. Fully supported. -=item always, always_comb, always_ff, always_latch, and, assign, begin, -buf, case, casex, casez, default, defparam, do-while, else, end, endcase, -endfunction, endgenerate, endmodule, endspecify, endtask, final, for, -function, generate, genvar, if, initial, inout, input, integer, localparam, -macromodule, module, nand, negedge, nor, not, or, output, parameter, -posedge, reg, scalared, signed, supply0, supply1, task, tri, vectored, -while, wire, xnor, xor +=item int, shortint, longint, always, always_comb, always_ff, always_latch, +and, assign, begin, buf, byte, case, casex, casez, default, defparam, +do-while, else, end, endcase, endfunction, endgenerate, endmodule, +endspecify, endtask, final, for, function, generate, genvar, if, initial, +inout, input, integer, logic, localparam, macromodule, module, nand, +negedge, nor, not, or, output, parameter, posedge, reg, scalared, signed, +supply0, supply1, task, tri, vectored, while, wire, xnor, xor Generally supported. diff --git a/src/V3Ast.h b/src/V3Ast.h index 0906186f9..a2351d85c 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -202,13 +202,16 @@ class AstBasicDTypeKwd { public: enum en { BYTE, SHORTINT, INT, LONGINT, INTEGER, TIME, BIT, - LOGIC, REG, SHORTREAL, REAL, REALTIME + LOGIC, SHORTREAL, REAL, REALTIME, + // Internal types + LOGIC_IMPLICIT }; enum en m_e; const char* ascii() const { static const char* names[] = { "byte", "shortint", "int", "longint", "integer", "time", "bit", - "logic", "reg", "shortreal", "real", "realtime" + "logic", "shortreal", "real", "realtime", + "LOGIC_IMPLICIT" }; return names[m_e]; }; @@ -216,6 +219,30 @@ public: inline AstBasicDTypeKwd (en _e) : m_e(_e) {} explicit inline AstBasicDTypeKwd (int _e) : m_e(static_cast(_e)) {} operator en () const { return m_e; } + int width() const { + switch (m_e) { + case BYTE: return 8; + case SHORTINT: return 16; + case INT: return 32; + case LONGINT: return 64; + case INTEGER: return 32; + case LOGIC: return 1; + case BIT: return 1; + default: return 0; + } + } + int isSigned() const { + return m_e==BYTE || m_e==SHORTINT || m_e==INT || m_e==LONGINT || m_e==INTEGER; + } + int isFourstate() const { + return m_e==INTEGER || m_e==LOGIC || m_e==LOGIC_IMPLICIT; + } + int isSloppy() const { // Don't be as anal about width warnings + return !(m_e==LOGIC || m_e==BIT); + } + int isBitLogic() const { // Don't be as anal about width warnings + return (m_e==LOGIC || m_e==BIT); + } }; inline bool operator== (AstBasicDTypeKwd lhs, AstBasicDTypeKwd rhs) { return (lhs.m_e == rhs.m_e); } inline bool operator== (AstBasicDTypeKwd lhs, AstBasicDTypeKwd::en rhs) { return (lhs.m_e == rhs); } @@ -244,7 +271,7 @@ public: SUPPLY0, SUPPLY1, WIRE, - IMPLICIT, + IMPLICITWIRE, TRIWIRE, PORT, // Temp type used in parser only BLOCKTEMP, @@ -261,7 +288,7 @@ public: static const char* names[] = { "?","GPARAM","LPARAM","GENVAR", "VAR","INPUT","OUTPUT","INOUT", - "SUPPLY0","SUPPLY1","WIRE","IMPLICIT","TRIWIRE","PORT", + "SUPPLY0","SUPPLY1","WIRE","IMPLICITWIRE","TRIWIRE","PORT", "BLOCKTEMP","MODULETEMP","STMTTEMP","XTEMP"}; return names[m_e]; } }; @@ -1176,12 +1203,13 @@ struct AstNodeSel : public AstNodeBiop { struct AstNodeFTask : public AstNode { private: string m_name; // Name of task - bool m_taskPublic; // Public task + bool m_taskPublic:1; // Public task + bool m_didSigning:1; // V3Signed completed; can skip iteration public: // Node that simply puts name into the output stream AstNodeFTask(FileLine* fileline, const string& name, AstNode* stmtsp) : AstNode(fileline) - , m_name(name), m_taskPublic(false) { + , m_name(name), m_taskPublic(false), m_didSigning(false) { addNOp3p(stmtsp); } ASTNODE_BASE_FUNCS(NodeFTask) @@ -1195,6 +1223,8 @@ public: void addStmtsp(AstNode* nodep) { addNOp3p(nodep); } void taskPublic(bool flag) { m_taskPublic=flag; } bool taskPublic() const { return m_taskPublic; } + void didSigning(bool flag) { m_didSigning=flag; } + bool didSigning() const { return m_didSigning; } }; struct AstNodeFTaskRef : public AstNode { diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 6565def1a..2c725f5e0 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -98,14 +98,12 @@ string AstVar::verilogKwd() const { return "input"; } else if (isOutput()) { return "output"; - } else if (isInteger()) { - return "integer"; } else if (isTristate()) { return "tri"; } else if (varType()==AstVarType::WIRE) { return "wire"; } else { - return "reg"; + return dtypep()->name(); } } @@ -327,6 +325,7 @@ void AstAttrOf::dump(ostream& str) { void AstBasicDType::dump(ostream& str) { this->AstNode::dump(str); str<<" ["<AstNode::dump(str); diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 8bdb83d85..c5a92fc59 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -109,6 +109,7 @@ struct AstBasicDType : public AstNodeDType { // Builtin atomic/vectored data type private: AstBasicDTypeKwd m_keyword; // What keyword created it + bool m_implicit; // Implicitly declared public: AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, AstRange* rangep=NULL, AstSignedState signst=signedst_NOP) : AstNodeDType(fl), m_keyword(kwd) { @@ -116,14 +117,24 @@ public: } private: void init(AstSignedState signst, AstRange* rangep) { - if (rangep==NULL) { // Set based on keyword properties - if (m_keyword == AstBasicDTypeKwd::INTEGER) { - rangep = new AstRange(fileline(),31,0); signst = signedst_SIGNED; - } + // Implicitness: // "parameter X" is implicit and sized from initial value, "parameter reg x" not + m_implicit = false; + if (keyword()==AstBasicDTypeKwd::LOGIC_IMPLICIT) { + if (!rangep) m_implicit = true; + m_keyword = AstBasicDTypeKwd::LOGIC; } - setNOp1p(rangep); setSignedState(signst); + if (signst == signedst_NOP && keyword().isSigned()) signst = signedst_SIGNED; + setSignedState(signst); + if (!rangep) { // Set based on keyword properties + // V3Width will pull from this width + if (keyword().width() > 1) rangep = new AstRange(fileline(), keyword().width()-1, 0); + width(keyword().width(), keyword().width()); + } else { + widthFrom(rangep); // Maybe unknown if parameters underneath it + } + setNOp1p(rangep); } - AstBasicDTypeKwd keyword() const { return m_keyword; } + AstBasicDTypeKwd keyword() const { return m_keyword; } // private - use isSomething accessors instead public: ASTNODE_NODE_FUNCS(BasicDType, BASICDTYPE) virtual void dump(ostream& str); @@ -137,13 +148,15 @@ public: if (signst!=signedst_NOP) isSigned(signst==signedst_SIGNED); } // METHODS - bool isInteger() const { return (keyword() == AstBasicDTypeKwd::INTEGER); } + bool isBitLogic() const { return keyword().isBitLogic(); } + bool isSloppy() const { return keyword().isSloppy(); } int msb() const { if (!rangep()) return 0; return rangep()->msbConst(); } int lsb() const { if (!rangep()) return 0; return rangep()->lsbConst(); } int msbEndianed() const { if (!rangep()) return 0; return littleEndian()?rangep()->lsbConst():rangep()->msbConst(); } int lsbEndianed() const { if (!rangep()) return 0; return littleEndian()?rangep()->msbConst():rangep()->lsbConst(); } int msbMaxSelect() const { return (lsb()<0 ? msb()-lsb() : msb()); } // Maximum value a [] select may index bool littleEndian() const { return (rangep() && rangep()->littleEndian()); } + bool implicit() const { return m_implicit; } }; struct AstArraySel : public AstNodeSel { @@ -384,12 +397,12 @@ public: bool isPrimaryIO() const { return m_primaryIO; } bool isPrimaryIn() const { return isPrimaryIO() && isInput(); } bool isIO() const { return (m_input||m_output); } - bool isSignal() const { return (varType()==AstVarType::WIRE || varType()==AstVarType::IMPLICIT + bool isSignal() const { return (varType()==AstVarType::WIRE || varType()==AstVarType::IMPLICITWIRE || varType()==AstVarType::VAR); } bool isTemp() const { return (varType()==AstVarType::BLOCKTEMP || varType()==AstVarType::MODULETEMP || varType()==AstVarType::STMTTEMP || varType()==AstVarType::XTEMP); } bool isToggleCoverable() const { return ((isIO() || isSignal()) - && (isIO() || !isInteger()) + && (isIO() || isBitLogic()) // Wrapper would otherwise duplicate wrapped module's coverage && !isSc() && !isPrimaryIO()); } bool isStatementTemp() const { return (varType()==AstVarType::STMTTEMP); } @@ -398,7 +411,7 @@ public: bool isParam() const { return (varType()==AstVarType::LPARAM || varType()==AstVarType::GPARAM); } bool isGParam() const { return (varType()==AstVarType::GPARAM); } bool isGenVar() const { return (varType()==AstVarType::GENVAR); } - bool isInteger() const { return dtypep()->castBasicDType() && dtypep()->castBasicDType()->isInteger(); } + bool isBitLogic() const { return dtypep()->castBasicDType() && dtypep()->castBasicDType()->isBitLogic(); } bool isUsedClock() const { return m_usedClock; } bool isUsedParam() const { return m_usedParam; } bool isSc() const { return m_sc; } diff --git a/src/V3Signed.cpp b/src/V3Signed.cpp index 3372da6a7..537a11721 100644 --- a/src/V3Signed.cpp +++ b/src/V3Signed.cpp @@ -138,7 +138,6 @@ private: //======= // These have proper signedness set when they were created. - virtual void visit(AstFunc* nodep, AstNUser*) { nodep->iterateChildren(*this); } virtual void visit(AstNodeDType* nodep, AstNUser*) { nodep->iterateChildren(*this); } // Inherit from others @@ -150,20 +149,28 @@ private: nodep->varp()->iterate(*this); nodep->signedFrom(nodep->varp()); } - virtual void visit(AstFuncRef* nodep, AstNUser* vup) { - visit(nodep->castNodeFTaskRef(), vup); // Deal with as if was task - nodep->signedFrom(nodep->taskp()); - } virtual void visit(AstConst* nodep, AstNUser*) { // The node got setup with the signed state of the node. // However a later operation may have changed the node->signed w/o changing // the number's sign. So we don't: nodep->isSigned(nodep->num().isSigned()); } - virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) { - // Fortunately, the input variables to the task keep whatever sign they are given - // And we already did the function's output signedness above in visit(AstFuncRef, - // so, it's just + virtual void visit(AstFunc* nodep, AstNUser*) { + // Avoid recursion; can't use user() as they're all full, and anyhow this is often called + if (nodep->didSigning()) return; + nodep->didSigning(true); nodep->iterateChildren(*this); + nodep->signedFrom(nodep->fvarp()); // Which will get it from fvarp()->dtypep() + } + virtual void visit(AstTask* nodep, AstNUser*) { + // Avoid recursion; can't use user() as they're all full, and anyhow this is often called + if (nodep->didSigning()) return; + nodep->didSigning(true); + nodep->iterateChildren(*this); + } + virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) { + nodep->iterateChildren(*this); + if (nodep->taskp()) nodep->taskp()->iterate(*this); + nodep->signedFrom(nodep->taskp()); } virtual void visit(AstNodeIf* nodep, AstNUser*) { if (!nodep->castGenIf()) { // for m_paramsOnly diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 61dfd2177..599799501 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -473,6 +473,14 @@ private: virtual void visit(AstScopeName* nodep, AstNUser* vup) { // Only used in Displays which don't care.... } + virtual void visit(AstBasicDType* nodep, AstNUser* vup) { + if (nodep->rangep()) { + nodep->rangep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); + nodep->widthFrom(nodep->rangep()); + } + // else width in node is correct; it was set based on keyword().width() + // at construction time + } virtual void visit(AstVar* nodep, AstNUser* vup) { //if (debug()) nodep->dumpTree(cout," InitPre: "); // Must have deterministic constant width @@ -480,27 +488,18 @@ private: // with non-constant range gets size 1, not size 0. int width=1; int mwidth=1; nodep->arraysp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); - if (nodep->dtypep()->rangep()) { - nodep->dtypep()->rangep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); - width = mwidth = nodep->dtypep()->rangep()->width(); - } - else if (nodep->isInteger() || nodep->isGenVar()) { - width = 32; - mwidth = 1; // Consider it unsized, as we want x[int] to work, and also want {int} to fail. - } - else if (nodep->isParam()) { // unranged - width = mwidth = 0; // But see below later. - } - if (nodep->initp()) { - nodep->initp()->iterateAndNext(*this,WidthVP(width,0,PRELIM).p()); - // Although nodep will get a different width for parameters just below, - // we want the init numbers to retain their width/minwidth until parameters are replaced. - nodep->initp()->iterateAndNext(*this,WidthVP(width,0,FINAL).p()); - if (nodep->isParam()) { - if (nodep->dtypep()->rangep()) { - // Parameters need to preserve widthMin from the value, not get a constant size - mwidth = nodep->initp()->widthMin(); - } else if (nodep->initp()->widthSized()) { + + // Parameters if implicit untyped inherit from what they are assigned to + AstBasicDType* bdtypep = nodep->dtypep()->castBasicDType(); + if (nodep->isParam() && bdtypep && bdtypep->implicit()) { + width = mwidth = 0; + if (nodep->initp()) { + nodep->initp()->iterateAndNext(*this,WidthVP(width,0,PRELIM).p()); + // Although nodep will get a different width for parameters just below, + // we want the init numbers to retain their width/minwidth until parameters are replaced. + // This prevents width warnings at the location the parameter is substituted in + nodep->initp()->iterateAndNext(*this,WidthVP(width,0,FINAL).p()); + if (nodep->initp()->widthSized()) { width = mwidth = nodep->initp()->width(); } else { if (nodep->initp()->width()>32) nodep->initp()->v3warn(WIDTH,"Assigning >32 bit to unranged parameter (defaults to 32 bits)\n"); @@ -508,34 +507,43 @@ private: mwidth = nodep->initp()->widthMin(); } } - //if (debug()) nodep->dumpTree(cout," final: "); - } - if (nodep->isParam() && !nodep->dtypep()->rangep()) { // Parameter sizes can come from the thing they get assigned from // They then "stick" to that width. if (!width) width=32; // Or, if nothing, they're 32 bits. - AstBasicDType* bdtypep = nodep->dtypep()->castBasicDType(); + if (bdtypep->rangep()) bdtypep->rangep()->unlinkFrBackWithNext()->deleteTree(); bdtypep->rangep(new AstRange(nodep->fileline(),width-1,0)); - bdtypep->rangep()->width(width,width); + nodep->dtypep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); + } + else { // non param or sized param + nodep->dtypep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); + width = nodep->dtypep()->width(); mwidth = nodep->dtypep()->widthMin(); + if (nodep->initp()) { + nodep->initp()->iterateAndNext(*this,WidthVP(width,0,BOTH).p()); + //if (debug()) nodep->dumpTree(cout," final: "); + } } nodep->width(width,mwidth); // See above note about initp()->...FINAL if (nodep->initp()) widthCheck(nodep,"Initial value",nodep->initp(),width,mwidth); UINFO(4,"varWidthed "<dumpTree(cout," InitPos: "); + //if (debug()) nodep->dumpTree(cout," InitOut: "); } virtual void visit(AstNodeVarRef* nodep, AstNUser* vup) { if (nodep->varp()->width()==0) { // Var hasn't been widthed, so make it so. nodep->varp()->iterate(*this); } - if ((nodep->varp()->isInteger() || nodep->varp()->isGenVar()) + //if (debug()>=9) { nodep->dumpTree(cout," VRin "); nodep->varp()->dumpTree(cout," forvar "); } + // Note genvar's are also entered as integers + AstBasicDType* bdtypep = nodep->varp()->dtypep()->castBasicDType(); + if (bdtypep && bdtypep->isSloppy() && nodep->backp()->castNodeAssign()) { // On LHS // Consider Integers on LHS to sized (else would be unsized.) - nodep->width(32,32); + nodep->width(bdtypep->width(),bdtypep->width()); } else { - nodep->width(nodep->varp()->width(), nodep->varp()->widthMin()); + nodep->widthFrom(nodep->varp()); } + //if (debug()>=9) nodep->dumpTree(cout," VRout "); } virtual void visit(AstPslClocked* nodep, AstNUser*) { nodep->propp()->iterateAndNext(*this,WidthVP(1,1,BOTH).p()); @@ -625,14 +633,14 @@ private: } nodep->condp()->iterateAndNext(*this,WidthVP(1,1,BOTH).p()); widthCheckReduce(nodep,"If",nodep->condp(),1,1); // it's like an if() condition. - //if (debug()) nodep->dumpTree(cout," IfPos: "); + //if (debug()) nodep->dumpTree(cout," IfOut: "); } virtual void visit(AstNodeAssign* nodep, AstNUser*) { // TOP LEVEL NODE //if (debug()) nodep->dumpTree(cout," AssignPre: "); nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); nodep->rhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p()); - if(!nodep->lhsp()->widthSized()) nodep->v3fatalSrc("How can LHS be unsized?"); + if (!nodep->lhsp()->widthSized()) nodep->v3fatalSrc("How can LHS be unsized?"); int awidth = nodep->lhsp()->width(); if (awidth==0) { awidth = nodep->rhsp()->width(); // Parameters can propagate by unsized assignment @@ -643,7 +651,7 @@ private: // than using "width" and have the optimizer truncate the result, we do // it using the normal width reduction checks. widthCheck(nodep,"Assign RHS",nodep->rhsp(),awidth,awidth); - //if (debug()) nodep->dumpTree(cout," AssignPos: "); + //if (debug()) nodep->dumpTree(cout," AssignOut: "); } virtual void visit(AstNodePli* nodep, AstNUser*) { // Excludes NodeDisplay, see below @@ -797,7 +805,7 @@ private: widthCheckPin(nodep, nodep->exprp(), pinwidth, inputPin); } } - //if (debug()) nodep->dumpTree(cout,"- PinPos: "); + //if (debug()) nodep->dumpTree(cout,"- PinOut: "); } virtual void visit(AstCell* nodep, AstNUser*) { if (!m_paramsOnly) { @@ -822,6 +830,7 @@ private: virtual void visit(AstFuncRef* nodep, AstNUser* vup) { visit(nodep->castNodeFTaskRef(), vup); nodep->widthSignedFrom(nodep->taskp()); + //if (debug()) nodep->dumpTree(cout," FuncOut: "); } virtual void visit(AstNodeFTaskRef* nodep, AstNUser* vup) { // Function hasn't been widthed, so make it so. diff --git a/src/verilog.l b/src/verilog.l index 3a738f7f1..7e236d8d3 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -196,6 +196,7 @@ escid \\[^ \t\f\r\n]+ "buf" { FL; return yBUF; } "bufif0" { FL; return yBUFIF0; } "bufif1" { FL; return yBUFIF1; } + "byte" { FL; return yBYTE; } "case" { FL; return yCASE; } "casex" { FL; return yCASEX; } "casez" { FL; return yCASEZ; } @@ -217,7 +218,9 @@ escid \\[^ \t\f\r\n]+ "initial" { FL; return yINITIAL; } "inout" { FL; return yINOUT; } "input" { FL; return yINPUT; } + "int" { FL; return yINT; } "integer" { FL; return yINTEGER; } + "longint" { FL; return yLONGINT; } "macromodule" { FL; return yMODULE; } "module" { FL; return yMODULE; } "nand" { FL; return yNAND; } @@ -235,6 +238,7 @@ escid \\[^ \t\f\r\n]+ "reg" { FL; return yREG; } "repeat" { FL; return yREPEAT; } "scalared" { FL; return ySCALARED; } + "shortint" { FL; return ySHORTINT; } "specify" { FL; return ySPECIFY; } "specparam" { FL; return ySPECPARAM; } "supply0" { FL; return ySUPPLY0; } @@ -382,7 +386,6 @@ escid \\[^ \t\f\r\n]+ "bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "binsof" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "break" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } - "byte" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "chandle" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "class" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "constraint" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } @@ -410,13 +413,11 @@ escid \\[^ \t\f\r\n]+ "illegal_bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "import" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "inside" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } - "int" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "interface" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "intersect" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "join_any" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "join_none" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "local" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } - "longint" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "matches" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "modport" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "new" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } @@ -433,7 +434,6 @@ escid \\[^ \t\f\r\n]+ "randsequence" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "ref" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "return" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } - "shortint" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "shortreal" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "solve" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "string" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } diff --git a/src/verilog.y b/src/verilog.y index 4a556f6bf..998348f6a 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -103,6 +103,7 @@ public: #define GRAMMARP V3ParseGrammar::singletonp() const AstBasicDTypeKwd LOGIC = AstBasicDTypeKwd::LOGIC; // Shorthand "LOGIC" +const AstBasicDTypeKwd LOGIC_IMPLICIT = AstBasicDTypeKwd::LOGIC_IMPLICIT; //====================================================================== // Macro functions @@ -208,6 +209,7 @@ class AstSenTree; %token yBUF "buf" %token yBUFIF0 "bufif0" %token yBUFIF1 "bufif1" +%token yBYTE "byte" %token yCASE "case" %token yCASEX "casex" %token yCASEZ "casez" @@ -235,12 +237,14 @@ class AstSenTree; %token yGENVAR "genvar" %token yIF "if" %token yIFF "iff" -%token yLOGIC "logic" %token yINITIAL "initial" %token yINOUT "inout" %token yINPUT "input" +%token yINT "int" %token yINTEGER "integer" %token yLOCALPARAM "localparam" +%token yLOGIC "logic" +%token yLONGINT "longint" %token yMODULE "module" %token yNAND "nand" %token yNEGEDGE "negedge" @@ -259,6 +263,7 @@ class AstSenTree; %token yREG "reg" %token yREPEAT "repeat" %token ySCALARED "scalared" +%token ySHORTINT "shortint" %token ySIGNED "signed" %token ySPECIFY "specify" %token ySPECPARAM "specparam" @@ -626,7 +631,7 @@ port: // ==IEEE: port portDirNetE data_type portSig variable_dimensionListE sigAttrListE { $$=$3; VARDTYPE($2); $$->addNextNull(VARDONEP($$,$4,$5)); } //UNSUP portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE { $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); } //UNSUP portDirNetE yVAR implicit_type portSig variable_dimensionListE sigAttrListE { $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); } - | portDirNetE signingE rangeList portSig variable_dimensionListE sigAttrListE { $$=$4; VARDTYPE(new AstBasicDType($3->fileline(), LOGIC, $3, $2)); $$->addNextNull(VARDONEP($$,$5,$6)); } + | portDirNetE signingE rangeList portSig variable_dimensionListE sigAttrListE { $$=$4; VARDTYPE(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $3, $2)); $$->addNextNull(VARDONEP($$,$5,$6)); } | portDirNetE /*implicit*/ portSig variable_dimensionListE sigAttrListE { $$=$2; /*VARDTYPE-same*/ $$->addNextNull(VARDONEP($$,$3,$4)); } // | portDirNetE data_type portSig variable_dimensionListE sigAttrListE '=' constExpr { $$=$3; VARDTYPE($2); $$->addNextNull(VARDONEP($$,$4,$5)); $$->addNextNull(GRAMMARP->newVarInit($6,$$,$7)); } @@ -693,13 +698,13 @@ parameter_declaration: // IEEE: parameter_declaration local_parameter_declarationFront: // IEEE: local_parameter_declaration w/o assignment varLParamReset implicit_type { /*VARRESET-in-varLParam*/ VARDTYPE($2); } - //UNSUP varLParamReset data_type { /*VARRESET-in-varLParam*/ VARDTYPE($2); } + | varLParamReset data_type { /*VARRESET-in-varLParam*/ VARDTYPE($2); } //UNSUP varLParamReset yTYPE { /*VARRESET-in-varLParam*/ VARDTYPE($2); } ; parameter_declarationFront: // IEEE: parameter_declaration w/o assignment varGParamReset implicit_type { /*VARRESET-in-varGParam*/ VARDTYPE($2); } - //UNSUP varGParamReset data_type { /*VARRESET-in-varGParam*/ VARDTYPE($2); } + | varGParamReset data_type { /*VARRESET-in-varGParam*/ VARDTYPE($2); } //UNSUP varGParamReset yTYPE { /*VARRESET-in-varGParam*/ VARDTYPE($2); } ; @@ -779,9 +784,9 @@ port_declaration: // ==IEEE: port_declaration list_of_variable_decl_assignments { $$ = $5; } //UNSUP port_directionReset port_declNetE yVAR data_type { VARDTYPE($4); } list_of_variable_decl_assignments { $$ = $6; } //UNSUP port_directionReset port_declNetE yVAR implicit_type { VARDTYPE($4); } list_of_variable_decl_assignments { $$ = $6; } - | port_directionReset port_declNetE signingE rangeList { VARDTYPE(new AstBasicDType($4->fileline(), LOGIC, $4, $3)); } + | port_directionReset port_declNetE signingE rangeList { VARDTYPE(new AstBasicDType($4->fileline(), LOGIC_IMPLICIT, $4, $3)); } list_of_variable_decl_assignments { $$ = $6; } - | port_directionReset port_declNetE signing { VARDTYPE(new AstBasicDType($3, LOGIC, NULL, $3)); } + | port_directionReset port_declNetE signing { VARDTYPE(new AstBasicDType($3, LOGIC_IMPLICIT, NULL, $3)); } list_of_variable_decl_assignments { $$ = $5; } | port_directionReset port_declNetE /*implicit*/ { VARDTYPE(NULL);/*default_nettype*/} list_of_variable_decl_assignments { $$ = $4; } @@ -798,18 +803,18 @@ tf_port_declaration: // ==IEEE: tf_port_declaration ; integer_atom_type: // ==IEEE: integer_atom_type - //UNSUP yBYTE { $$ = new AstBasicDType($1,AstBasicDTypeKwd::BYTE); } - //UNSUP ySHORTINT { $$ = new AstBasicDType($1,AstBasicDTypeKwd::SHORTINT); } - //UNSUP yINT { $$ = new AstBasicDType($1,AstBasicDTypeKwd::INT); } - //UNSUP yLONGINT { $$ = new AstBasicDType($1,AstBasicDTypeKwd::LONGINT); } - yINTEGER { $$ = new AstBasicDType($1,AstBasicDTypeKwd::INTEGER); } + yBYTE { $$ = new AstBasicDType($1,AstBasicDTypeKwd::BYTE); } + | ySHORTINT { $$ = new AstBasicDType($1,AstBasicDTypeKwd::SHORTINT); } + | yINT { $$ = new AstBasicDType($1,AstBasicDTypeKwd::INT); } + | yLONGINT { $$ = new AstBasicDType($1,AstBasicDTypeKwd::LONGINT); } + | yINTEGER { $$ = new AstBasicDType($1,AstBasicDTypeKwd::INTEGER); } //UNSUP yTIME { $$ = new AstBasicDType($1,AstBasicDTypeKwd::TIME); } ; integer_vector_type: // ==IEEE: integer_atom_type yBIT { $$ = new AstBasicDType($1,AstBasicDTypeKwd::BIT); } | yLOGIC { $$ = new AstBasicDType($1,AstBasicDTypeKwd::LOGIC); } - | yREG { $$ = new AstBasicDType($1,AstBasicDTypeKwd::REG); } + | yREG { $$ = new AstBasicDType($1,AstBasicDTypeKwd::LOGIC); } // logic==reg ; signingE: // IEEE: signing - plus empty @@ -961,8 +966,8 @@ data_declarationVarFront: // IEEE: part of data_declaration implicit_type: // IEEE: part of *data_type_or_implicit // // Also expanded in data_declaration /* empty */ { $$ = NULL; } - | signingE rangeList { $$ = new AstBasicDType($2->fileline(), LOGIC, $2, $1); } - | signing { $$ = new AstBasicDType($1, LOGIC, NULL, $1); } + | signingE rangeList { $$ = new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $2, $1); } + | signing { $$ = new AstBasicDType($1, LOGIC_IMPLICIT, NULL, $1); } ; //************************************************ @@ -1240,9 +1245,9 @@ rangeList: // IEEE: {packed_dimension} | rangeList anyrange { $$ = $1; $1->addNext($2); } ; -regrangeE: - /* empty */ { $$ = new AstBasicDType(CRELINE(), LOGIC, NULL); } - | anyrange { $$ = new AstBasicDType(CRELINE(), LOGIC, $1); } +wirerangeE: + /* empty */ { $$ = new AstBasicDType(CRELINE(), LOGIC, NULL); } // not implicit + | anyrange { $$ = new AstBasicDType(CRELINE(), LOGIC, $1); } // not implicit ; // IEEE: select @@ -1253,9 +1258,9 @@ anyrange: ; delayrange: - regrangeE delayE { $$ = $1; } - | ySCALARED regrangeE delayE { $$ = $2; } - | yVECTORED regrangeE delayE { $$ = $2; } + wirerangeE delayE { $$ = $1; } + | ySCALARED wirerangeE delayE { $$ = $2; } + | yVECTORED wirerangeE delayE { $$ = $2; } //UNSUP: ySCALARED/yVECTORED ignored ; @@ -1744,15 +1749,17 @@ task_declaration: // ==IEEE: task_declaration ; function_declaration: // IEEE: function_declaration + function_body_declaration - yFUNCTION lifetimeE funcTypeE funcId tfGuts yENDFUNCTION endLabelE - { $$ = $4; $$->addFvarp($3); $$->addStmtsp($5); if ($3) $$->isSigned($3->isSigned()); - SYMP->popScope($$); } - | yFUNCTION lifetimeE funcTypeE funcId yVL_ISOLATE_ASSIGNMENTS tfGuts yENDFUNCTION endLabelE - { $$ = $4; $$->addFvarp($3); $$->addStmtsp($6); $$->attrIsolateAssign(true); if ($3) $$->isSigned($3->isSigned()); + yFUNCTION lifetimeE funcId funcIsolateE tfGuts yENDFUNCTION endLabelE + { $$ = $3; $$->attrIsolateAssign($4); $$->addStmtsp($5); SYMP->popScope($$); } //UNSUP: Generic function return types ; +funcIsolateE: + /* empty */ { $$ = 0; } + | yVL_ISOLATE_ASSIGNMENTS { $$ = 1; } + ; + lifetimeE: // IEEE: [lifetime] /* empty */ { } | lifetime { } @@ -1773,11 +1780,23 @@ taskId: funcId: // IEEE: function_data_type_or_implicit + part of function_body_declaration // // IEEE: function_data_type_or_implicit must be expanded here to prevent conflict // // function_data_type expanded here to prevent conflicts with implicit_type:empty vs data_type:ID - tfIdScoped + /**/ tfIdScoped { $$ = new AstFunc ($1,*$1,NULL,NULL); + $$->addFvarp(new AstBasicDType($$->fileline(), LOGIC_IMPLICIT, NULL)); + SYMP->pushNewUnder($$, NULL); } + | signingE rangeList tfIdScoped + { $$ = new AstFunc ($3,*$3,NULL,NULL); + $$->addFvarp(new AstBasicDType($$->fileline(), LOGIC_IMPLICIT, $2, $1)); + SYMP->pushNewUnder($$, NULL); } + | signing tfIdScoped + { $$ = new AstFunc ($2,*$2,NULL,NULL); + $$->addFvarp(new AstBasicDType($$->fileline(), LOGIC_IMPLICIT, NULL, $1)); + SYMP->pushNewUnder($$, NULL); } + //UNSUP yVOID tfIdScoped { UNSUP } + | data_type tfIdScoped + { $$ = new AstFunc ($2,*$2,NULL,NULL); + $$->addFvarp($1); SYMP->pushNewUnder($$, NULL); } - //UNSUP id/*interface_identifier*/ '.' id { UNSUP } - //UNSUP class_scope_id { UNSUP } ; tfIdScoped: // IEEE: part of function_body_declaration/task_body_declaration @@ -1799,14 +1818,6 @@ tfBodyE: // IEEE: part of function_body_declaration/task_body_declarati | stmtList { $$ = $1; } ; -funcTypeE: - /* empty */ { $$ = NULL; } - | yINTEGER { $$ = new AstBasicDType($1,AstBasicDTypeKwd::INTEGER); } - | ySIGNED { $$ = new AstBasicDType($1,LOGIC, NULL); $$->isSigned(true); } - | ySIGNED '[' constExpr ':' constExpr ']' { $$ = new AstBasicDType($1,LOGIC, new AstRange($1,$3,$5)); $$->isSigned(true); } - | '[' constExpr ':' constExpr ']' { $$ = new AstBasicDType($1,LOGIC, new AstRange($1,$2,$4)); } - ; - tf_item_declarationList: tf_item_declaration { $$ = $1; } | tf_item_declarationList tf_item_declaration { $$ = $1->addNextNull($2); } @@ -1842,15 +1853,15 @@ tf_port_item: // ==IEEE: tf_port_item tf_port_itemFront: // IEEE: part of tf_port_item, which has the data type data_type { VARDTYPE($1); } - | signingE rangeList { VARDTYPE(new AstBasicDType($2->fileline(), LOGIC, $2, $1)); } - | signing { VARDTYPE(new AstBasicDType($1, LOGIC, NULL, $1)); } + | signingE rangeList { VARDTYPE(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $2, $1)); } + | signing { VARDTYPE(new AstBasicDType($1, LOGIC_IMPLICIT, NULL, $1)); } //UNSUP yVAR data_type { VARDTYPE($2); } //UNSUP yVAR implicit_type { VARDTYPE($2); } // | tf_port_itemDir /*implicit*/ { VARDTYPE(NULL); /*default_nettype-see spec*/ } | tf_port_itemDir data_type { VARDTYPE($2); } - | tf_port_itemDir signingE rangeList { VARDTYPE(new AstBasicDType($3->fileline(), LOGIC, $3, $2)); } - | tf_port_itemDir signing { VARDTYPE(new AstBasicDType($2, LOGIC, NULL, $2)); } + | tf_port_itemDir signingE rangeList { VARDTYPE(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $3, $2)); } + | tf_port_itemDir signing { VARDTYPE(new AstBasicDType($2, LOGIC_IMPLICIT, NULL, $2)); } //UNSUP tf_port_itemDir yVAR data_type { VARDTYPE($3); } //UNSUP tf_port_itemDir yVAR implicit_type { VARDTYPE($3); } ; @@ -2588,8 +2599,7 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, string name, AstRange } AstVarType type = GRAMMARP->m_varIO; if (!dtypep) { // Created implicitly - // We also make them for standalone ports, which is a bit silly, but we'll clean up later - dtypep = new AstBasicDType(fileline, LOGIC); + dtypep = new AstBasicDType(fileline, LOGIC_IMPLICIT); } else { // May make new variables with same type, so clone dtypep = dtypep->cloneTree(false); } diff --git a/test_regress/t/t_var_logic.v b/test_regress/t/t_var_logic.v deleted file mode 100644 index 9405dccd2..000000000 --- a/test_regress/t/t_var_logic.v +++ /dev/null @@ -1,83 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed into the Public Domain, for any use, -// without warranty, 2009 by Wilson Snyder. - -module t (/*AUTOARG*/ - // Inputs - clk - ); - input clk; - - - integer cyc=0; - // Test that we can actually use the logic keyword without an error popping up - //reg [63:0] crc; - logic [63:0] crc; - reg [63:0] sum; - - - // Take CRC data and apply to testblock inputs - wire [31:0] in = crc[31:0]; - - /*AUTOWIRE*/ - // Beginning of automatic wires (for undeclared instantiated-module outputs) - wire [31:0] out; // From test of Test.v - // End of automatics - - Test test (/*AUTOINST*/ - // Outputs - .out (out[31:0]), - // Inputs - .clk (clk), - .in (in[31:0])); - - // Aggregate outputs into a single result vector - wire [63:0] result = {32'h0, out}; - - // Test loop - always @ (posedge clk) begin -`ifdef TEST_VERBOSE - $write("[%0t] cyc==%0d crc=%x result=%x\n",$time, cyc, crc, result); -`endif - cyc <= cyc + 1; - crc <= {crc[62:0], crc[63]^crc[2]^crc[0]}; - sum <= result ^ {sum[62:0],sum[63]^sum[2]^sum[0]}; - if (cyc==0) begin - // Setup - crc <= 64'h5aef0c8d_d70a4497; - sum <= 64'h0; - end - else if (cyc<10) begin - sum <= 64'h0; - end - else if (cyc<90) begin - end - else if (cyc==99) begin - $write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum); - if (crc !== 64'hc77bb9b3784ea091) $stop; - // What checksum will we end up with (above print should match) -`define EXPECTED_SUM 64'h4afe43fb79d7b71e - if (sum !== `EXPECTED_SUM) $stop; - $write("*-* All Finished *-*\n"); - $finish; - end - end - -endmodule - -module Test (/*AUTOARG*/ - // Outputs - out, - // Inputs - clk, in - ); - - input clk; - input [31:0] in; - output reg [31:0] out; - - always @(posedge clk) begin - out <= in; - end -endmodule diff --git a/test_regress/t/t_var_logic.pl b/test_regress/t/t_var_types.pl similarity index 100% rename from test_regress/t/t_var_logic.pl rename to test_regress/t/t_var_types.pl diff --git a/test_regress/t/t_var_types.v b/test_regress/t/t_var_types.v new file mode 100644 index 000000000..7ac3538b2 --- /dev/null +++ b/test_regress/t/t_var_types.v @@ -0,0 +1,133 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2009 by Wilson Snyder. + +module t (/*AUTOARG*/); + + // IEEE: integer_atom_type + byte d_byte; + shortint d_shortint; + int d_int; + longint d_longint; + integer d_integer; + //UNSUP time d_time; + + // IEEE: integer_atom_type + bit d_bit; + logic d_logic; + reg d_reg; + + bit [1:0] d_bit2; + logic [1:0] d_logic2; + reg [1:0] d_reg2; + + // IEEE: non_integer_type + //UNSUP shortreal d_shortreal; + //UNSUP real d_real; + //UNSUP realtime d_realtime; + + // verilator lint_off WIDTH + localparam p_implicit = {96{1'b1}}; + localparam [89:0] p_explicit = {96{1'b1}}; + localparam byte p_byte = {96{1'b1}}; + localparam shortint p_shortint = {96{1'b1}}; + localparam int p_int = {96{1'b1}}; + localparam longint p_longint = {96{1'b1}}; + localparam integer p_integer = {96{1'b1}}; + localparam reg p_reg = {96{1'b1}}; + localparam bit p_bit = {96{1'b1}}; + localparam logic p_logic = {96{1'b1}}; + localparam reg [1:0] p_reg2 = {96{1'b1}}; + localparam bit [1:0] p_bit2 = {96{1'b1}}; + localparam logic [1:0] p_logic2= {96{1'b1}}; + // verilator lint_on WIDTH + + // verilator lint_off WIDTH + function f_implicit; f_implicit = {96{1'b1}}; endfunction + function [89:0] f_explicit; f_explicit = {96{1'b1}}; endfunction + function byte f_byte; f_byte = {96{1'b1}}; endfunction + function shortint f_shortint; f_shortint = {96{1'b1}}; endfunction + function int f_int; f_int = {96{1'b1}}; endfunction + function longint f_longint; f_longint = {96{1'b1}}; endfunction + function integer f_integer; f_integer = {96{1'b1}}; endfunction + function reg f_reg; f_reg = {96{1'b1}}; endfunction + function bit f_bit; f_bit = {96{1'b1}}; endfunction + function logic f_logic; f_logic = {96{1'b1}}; endfunction + function reg [1:0] f_reg2; f_reg2 = {96{1'b1}}; endfunction + function bit [1:0] f_bit2; f_bit2 = {96{1'b1}}; endfunction + function logic [1:0] f_logic2; f_logic2 = {96{1'b1}}; endfunction + // verilator lint_on WIDTH + +`define CHECK_ALL(name,bits,issigned,twostate) \ + name = {96{1'b1}}; \ + if (name !== {(bits){1'b1}}) begin $display("%%Error: Bad size for %s",`"name`"); $stop; end \ + if (issigned ? (name > 0) : (name < 0)) begin $display("%%Error: Bad signed for %s",`"name`"); $stop; end \ + name = {96{1'bx}}; \ + +//Everything is twostate in Verilator +// if (name !== {(bits){twostate ? 1'b0 : 1'bx}}) begin $display("%%Error: Bad twostate for %s",`"name`"); $stop; end \ + + initial begin + // verilator lint_off WIDTH + // verilator lint_off UNSIGNED + // name b sign twost + `CHECK_ALL(d_byte ,8 ,1'b1,1'b1); + `CHECK_ALL(d_shortint ,16,1'b1,1'b1); + `CHECK_ALL(d_int ,32,1'b1,1'b1); + `CHECK_ALL(d_longint ,64,1'b1,1'b1); + `CHECK_ALL(d_integer ,32,1'b1,1'b0); + `CHECK_ALL(d_bit ,1 ,1'b0,1'b1); + `CHECK_ALL(d_logic ,1 ,1'b0,1'b0); + `CHECK_ALL(d_reg ,1 ,1'b0,1'b0); + `CHECK_ALL(d_bit2 ,2 ,1'b0,1'b1); + `CHECK_ALL(d_logic2 ,2 ,1'b0,1'b0); + `CHECK_ALL(d_reg2 ,2 ,1'b0,1'b0); + // verilator lint_on WIDTH + // verilator lint_on UNSIGNED + +`define CHECK_P(name,bits) \ + if (name !== {(bits){1'b1}}) begin $display("%%Error: Bad size for %s",`"name`"); $stop; end \ + + `CHECK_P(p_implicit ,96); + `CHECK_P(p_explicit ,90); + `CHECK_P(p_byte ,8 ); + `CHECK_P(p_shortint ,16); + `CHECK_P(p_int ,32); + `CHECK_P(p_longint ,64); + `CHECK_P(p_integer ,32); + `CHECK_P(p_bit ,1 ); + `CHECK_P(p_logic ,1 ); + `CHECK_P(p_reg ,1 ); + `CHECK_P(p_bit2 ,2 ); + `CHECK_P(p_logic2 ,2 ); + `CHECK_P(p_reg2 ,2 ); + +`define CHECK_F(name,bits) \ + if (name() !== {(bits){1'b1}}) begin $display("%%Error: Bad size for %s",`"name`"); $stop; end \ + + `CHECK_F(f_implicit ,1 ); // Note 1 bit, not 96 + `CHECK_F(f_explicit ,90); + `CHECK_F(f_byte ,8 ); + `CHECK_F(f_shortint ,16); + `CHECK_F(f_int ,32); + `CHECK_F(f_longint ,64); + `CHECK_F(f_integer ,32); + `CHECK_F(f_bit ,1 ); + `CHECK_F(f_logic ,1 ); + `CHECK_F(f_reg ,1 ); + `CHECK_F(f_bit2 ,2 ); + `CHECK_F(f_logic2 ,2 ); + `CHECK_F(f_reg2 ,2 ); + + // For unpacked types we don't want width warnings for unsized numbers that fit + d_byte = 2; + d_shortint= 2; + d_int = 2; + d_longint = 2; + d_integer = 2; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule