Support byte, shortint, int, longint in variables, parameters and functions.

Internals: function/var sizing and signing now comes via dtypep()
Internals: cleanup code that widths parameters (again)
This commit is contained in:
Wilson Snyder 2009-11-02 22:14:11 -05:00
parent 4c26792c9b
commit 6bc81d3d26
12 changed files with 321 additions and 198 deletions

View File

@ -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;").

View File

@ -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.

View File

@ -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<en>(_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 {

View File

@ -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<<" ["<<keyword().ascii()<<"]";
if (implicit()) str<<" [IMPLICIT]";
}
void AstCast::dump(ostream& str) {
this->AstNode::dump(str);

View File

@ -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; }

View File

@ -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

View File

@ -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 "<<nodep<<endl);
//if (debug()) nodep->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.

View File

@ -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); }

View File

@ -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<fl> yBUF "buf"
%token<fl> yBUFIF0 "bufif0"
%token<fl> yBUFIF1 "bufif1"
%token<fl> yBYTE "byte"
%token<fl> yCASE "case"
%token<fl> yCASEX "casex"
%token<fl> yCASEZ "casez"
@ -235,12 +237,14 @@ class AstSenTree;
%token<fl> yGENVAR "genvar"
%token<fl> yIF "if"
%token<fl> yIFF "iff"
%token<fl> yLOGIC "logic"
%token<fl> yINITIAL "initial"
%token<fl> yINOUT "inout"
%token<fl> yINPUT "input"
%token<fl> yINT "int"
%token<fl> yINTEGER "integer"
%token<fl> yLOCALPARAM "localparam"
%token<fl> yLOGIC "logic"
%token<fl> yLONGINT "longint"
%token<fl> yMODULE "module"
%token<fl> yNAND "nand"
%token<fl> yNEGEDGE "negedge"
@ -259,6 +263,7 @@ class AstSenTree;
%token<fl> yREG "reg"
%token<fl> yREPEAT "repeat"
%token<fl> ySCALARED "scalared"
%token<fl> ySHORTINT "shortint"
%token<fl> ySIGNED "signed"
%token<fl> ySPECIFY "specify"
%token<fl> ySPECPARAM "specparam"
@ -626,7 +631,7 @@ port<nodep>: // ==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<nodep>: // 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<nodep>: // ==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($<fl>3, LOGIC, NULL, $3)); }
| port_directionReset port_declNetE signing { VARDTYPE(new AstBasicDType($<fl>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<nodep>: // ==IEEE: tf_port_declaration
;
integer_atom_type<bdtypep>: // ==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<bdtypep>: // ==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<signstate>: // IEEE: signing - plus empty
@ -961,8 +966,8 @@ data_declarationVarFront: // IEEE: part of data_declaration
implicit_type<typep>: // 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($<fl>1, LOGIC, NULL, $1); }
| signingE rangeList { $$ = new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $2, $1); }
| signing { $$ = new AstBasicDType($<fl>1, LOGIC_IMPLICIT, NULL, $1); }
;
//************************************************
@ -1240,9 +1245,9 @@ rangeList<rangep>: // IEEE: {packed_dimension}
| rangeList anyrange { $$ = $1; $1->addNext($2); }
;
regrangeE<bdtypep>:
/* empty */ { $$ = new AstBasicDType(CRELINE(), LOGIC, NULL); }
| anyrange { $$ = new AstBasicDType(CRELINE(), LOGIC, $1); }
wirerangeE<bdtypep>:
/* empty */ { $$ = new AstBasicDType(CRELINE(), LOGIC, NULL); } // not implicit
| anyrange { $$ = new AstBasicDType(CRELINE(), LOGIC, $1); } // not implicit
;
// IEEE: select
@ -1253,9 +1258,9 @@ anyrange<rangep>:
;
delayrange<bdtypep>:
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<taskp>: // ==IEEE: task_declaration
;
function_declaration<funcp>: // 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<cint>:
/* empty */ { $$ = 0; }
| yVL_ISOLATE_ASSIGNMENTS { $$ = 1; }
;
lifetimeE: // IEEE: [lifetime]
/* empty */ { }
| lifetime { }
@ -1773,11 +1780,23 @@ taskId<taskp>:
funcId<funcp>: // 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 ($<fl>1,*$<strp>1,NULL,NULL);
$$->addFvarp(new AstBasicDType($$->fileline(), LOGIC_IMPLICIT, NULL));
SYMP->pushNewUnder($$, NULL); }
| signingE rangeList tfIdScoped
{ $$ = new AstFunc ($<fl>3,*$<strp>3,NULL,NULL);
$$->addFvarp(new AstBasicDType($$->fileline(), LOGIC_IMPLICIT, $2, $1));
SYMP->pushNewUnder($$, NULL); }
| signing tfIdScoped
{ $$ = new AstFunc ($<fl>2,*$<strp>2,NULL,NULL);
$$->addFvarp(new AstBasicDType($$->fileline(), LOGIC_IMPLICIT, NULL, $1));
SYMP->pushNewUnder($$, NULL); }
//UNSUP yVOID tfIdScoped { UNSUP }
| data_type tfIdScoped
{ $$ = new AstFunc ($<fl>2,*$<strp>2,NULL,NULL);
$$->addFvarp($1);
SYMP->pushNewUnder($$, NULL); }
//UNSUP id/*interface_identifier*/ '.' id { UNSUP }
//UNSUP class_scope_id { UNSUP }
;
tfIdScoped<strp>: // IEEE: part of function_body_declaration/task_body_declaration
@ -1799,14 +1818,6 @@ tfBodyE<nodep>: // IEEE: part of function_body_declaration/task_body_declarati
| stmtList { $$ = $1; }
;
funcTypeE<typep>:
/* 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<nodep>:
tf_item_declaration { $$ = $1; }
| tf_item_declarationList tf_item_declaration { $$ = $1->addNextNull($2); }
@ -1842,15 +1853,15 @@ tf_port_item<nodep>: // ==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($<fl>1, LOGIC, NULL, $1)); }
| signingE rangeList { VARDTYPE(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $2, $1)); }
| signing { VARDTYPE(new AstBasicDType($<fl>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($<fl>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($<fl>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);
}

View File

@ -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

View File

@ -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