diff --git a/Changes b/Changes index 65177c2b3..92f1d8734 100644 --- a/Changes +++ b/Changes @@ -8,6 +8,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Error continuation lines no longer have %Error prefix. +**** Support logical equivalence operator <->. + **** Support VerilatedFstC set_time_unit, bug1433. [Pieter Kapsenberg] **** Support deferred assertions, bug1449. [Charles Eddleston] diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index a1aa673f4..66be9206b 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -4375,16 +4375,18 @@ public: virtual bool sizeMattersRhs() { return false; } virtual int instrCount() const { return widthInstrs()+instrCountBranch(); } }; -class AstLogIf : public AstNodeBiop { +class AstLogEq : public AstNodeBiCom { public: - AstLogIf(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { + AstLogEq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiCom(fl, lhsp, rhsp) { dtypeSetLogicBool(); } - ASTNODE_NODE_FUNCS(LogIf) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstLogIf(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLogIf(lhs, rhs); } - virtual string emitVerilog() { return "%k(%l %f-> %r)"; } - virtual string emitC() { return "VL_LOGIF_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() { return "->"; } + ASTNODE_NODE_FUNCS(LogEq) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstLogEq(this->fileline(), lhsp, rhsp); } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opLogEq(lhs, rhs); } + virtual string emitVerilog() { return "%k(%l %f<-> %r)"; } + virtual string emitC() { return "VL_LOGEQ_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + virtual string emitSimpleOperator() { return "<->"; } virtual bool cleanOut() { return true; } virtual bool cleanLhs() { return true; } virtual bool cleanRhs() { return true; } @@ -4392,16 +4394,18 @@ public: virtual bool sizeMattersRhs() { return false; } virtual int instrCount() const { return widthInstrs()+instrCountBranch(); } }; -class AstLogIff : public AstNodeBiCom { +class AstLogIf : public AstNodeBiop { public: - AstLogIff(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiCom(fl, lhsp, rhsp) { + AstLogIf(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeSetLogicBool(); } - ASTNODE_NODE_FUNCS(LogIff) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstLogIff(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLogIff(lhs, rhs); } - virtual string emitVerilog() { return "%k(%l %f<-> %r)"; } - virtual string emitC() { return "VL_LOGIFF_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() { return "<->"; } + ASTNODE_NODE_FUNCS(LogIf) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstLogIf(this->fileline(), lhsp, rhsp); } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opLogIf(lhs, rhs); } + virtual string emitVerilog() { return "%k(%l %f-> %r)"; } + virtual string emitC() { return "VL_LOGIF_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + virtual string emitSimpleOperator() { return "->"; } virtual bool cleanOut() { return true; } virtual bool cleanLhs() { return true; } virtual bool cleanRhs() { return true; } diff --git a/src/V3Const.cpp b/src/V3Const.cpp index e8ddb47c7..9bd55a591 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1345,6 +1345,23 @@ private: iterateChildren(nodep); } + void replaceLogEq(AstLogEq* nodep) { + // LOGEQ(a,b) => AstLogAnd{AstLogOr{AstLogNot{a},b},AstLogOr{AstLogNot{b},a}} + AstNode* lhsp = nodep->lhsp()->unlinkFrBack(); + AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); + // Do exactly as IEEE says, might result in extra terms, so in future may do differently + AstLogAnd* newp = new AstLogAnd(nodep->fileline(), + new AstLogOr(nodep->fileline(), + new AstLogNot(nodep->fileline(), lhsp), + rhsp), + new AstLogOr(nodep->fileline(), + new AstLogNot(nodep->fileline(), + rhsp->cloneTree(false)), + lhsp->cloneTree(false))); + newp->dtypeFrom(nodep); + nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep); + } + void replaceSelSel(AstSel* nodep) { // SEL(SEL({x},a,b),c,d) => SEL({x},a+c,d) AstSel* belowp = VN_CAST(nodep->fromp(), Sel); @@ -2455,9 +2472,9 @@ private: // Conversions TREEOPV("AstRedXnor{$lhsp}", "AstNot{AstRedXor{$lhsp}}"); // Just eliminate XNOR's // This visit function here must allow for short-circuiting. - TREEOPS("AstLogIf {$lhsp.isZero}", "replaceNum(nodep, 1)"); - TREEOPV("AstLogIf {$lhsp, $rhsp}", "AstLogOr{AstLogNot{$lhsp},$rhsp}"); - TREEOPV("AstLogIff{$lhsp, $rhsp}", "AstLogNot{AstXor{$lhsp,$rhsp}}"); + TREEOPS("AstLogIf{$lhsp.isZero}", "replaceNum(nodep, 1)"); + TREEOPV("AstLogIf{$lhsp, $rhsp}", "AstLogOr{AstLogNot{$lhsp},$rhsp}"); + TREEOPV("AstLogEq{$lhsp, $rhsp}", "replaceLogEq(nodep)"); // Strings TREEOPC("AstCvtPackString{$lhsp.castConst}", "replaceConstString(nodep, VN_CAST(nodep->lhsp(), Const)->num().toString())"); diff --git a/src/V3Number.cpp b/src/V3Number.cpp index 32d17f645..e4abd9f10 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -1115,14 +1115,17 @@ last: V3Number& V3Number::opLogIf(const V3Number& lhs, const V3Number& rhs) { // i op j, 1 bit return, max(L(lhs),L(rhs)) calculation, careful need to - // X/Z extend. Use opLogNot and opLogOr to do this for us. - return opLogOr(opLogNot(lhs), rhs); + // X/Z extend. Use definition in IEEE to do this for us. + V3Number lnot = lhs; lnot.opLogNot(lhs); + return opLogOr(lnot, rhs); } -V3Number& V3Number::opLogIff(const V3Number& lhs, const V3Number& rhs) { +V3Number& V3Number::opLogEq(const V3Number& lhs, const V3Number& rhs) { // i op j, 1 bit return, max(L(lhs),L(rhs)) calculation, careful need to - // X/Z extend. Use opLogNot and opLogXor to do this for us. - return opLogNot(opXor(lhs, rhs)); + // X/Z extend. Use definition in IEEE to do this for us. + V3Number ifa = lhs; ifa.opLogIf(lhs, rhs); + V3Number ifb = rhs; ifb.opLogIf(rhs, lhs); + return opLogAnd(ifa, ifb); } V3Number& V3Number::opEq(const V3Number& lhs, const V3Number& rhs) { diff --git a/src/V3Number.h b/src/V3Number.h index 50cf29d61..d1e63e9f9 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -301,8 +301,8 @@ public: V3Number& opLogNot (const V3Number& lhs); V3Number& opLogAnd (const V3Number& lhs, const V3Number& rhs); V3Number& opLogOr (const V3Number& lhs, const V3Number& rhs); + V3Number& opLogEq (const V3Number& lhs, const V3Number& rhs); V3Number& opLogIf (const V3Number& lhs, const V3Number& rhs); - V3Number& opLogIff (const V3Number& lhs, const V3Number& rhs); V3Number& opAbsS (const V3Number& lhs); V3Number& opNegate (const V3Number& lhs); V3Number& opAdd (const V3Number& lhs, const V3Number& rhs); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index b6823afd5..3dbc97562 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -223,8 +223,8 @@ private: // Widths: 1 bit out, lhs 1 bit, rhs 1 bit; Real: converts via compare with 0 virtual void visit(AstLogAnd* nodep) { visit_log_and_or(nodep); } virtual void visit(AstLogOr* nodep) { visit_log_and_or(nodep); } + virtual void visit(AstLogEq* nodep) { visit_log_and_or(nodep); } // Conversion from real not in IEEE, but a fallout virtual void visit(AstLogIf* nodep) { visit_log_and_or(nodep); } // Conversion from real not in IEEE, but a fallout - virtual void visit(AstLogIff* nodep) { visit_log_and_or(nodep); } // Conversion from real not in IEEE, but a fallout // Widths: 1 bit out, Any width lhs virtual void visit(AstRedAnd* nodep) { visit_red_and_or(nodep); } @@ -2803,7 +2803,7 @@ private: } } void visit_log_and_or(AstNodeBiop* nodep) { - // CALLER: LogAnd, LogOr, LogIf, LogIff + // CALLER: LogAnd, LogOr, LogEq, LogIf // Widths: 1 bit out, lhs 1 bit, rhs 1 bit // IEEE-2012 Table 11-21: // LHS is self-determined diff --git a/src/verilog.l b/src/verilog.l index d966a6212..99031c6c3 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -843,6 +843,11 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "["{ws}*"->" { FL; return yP_BRAMINUSGT; } } + /* SystemVerilog 2009 Operators */ +{ + "<->" { FL; return yP_LTMINUSGT; } +} + /* Identifiers and numbers */ { {escid} { FL; yylval.strp = PARSEP->newString diff --git a/src/verilog.y b/src/verilog.y index f9843b8c1..c824c7841 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -587,6 +587,7 @@ class AstSenTree; %token yP_PAR__STRENGTH "(-for-strength" +%token yP_LTMINUSGT "<->" %token yP_PLUSCOLON "+:" %token yP_MINUSCOLON "-:" %token yP_MINUSGT "->" @@ -621,8 +622,6 @@ class AstSenTree; %token yP_SRIGHTEQ ">>=" %token yP_SSRIGHTEQ ">>>=" -%token yP_LOGIFF - // [* is not a operator, as "[ * ]" is legal // [= and [-> could be repitition operators, but to match [* we don't add them. // '( is not a operator, as "' (" is legal @@ -632,10 +631,10 @@ class AstSenTree; %left yP_ANDANDAND // PSL op precedence -%right yP_MINUSGT yP_LOGIFF -%right yP_ORMINUSGT yP_OREQGT +%right yP_ORMINUSGT yP_OREQGT // Verilog op precedence +%right yP_MINUSGT yP_LTMINUSGT %right '?' ':' %left yP_OROR %left yP_ANDAND @@ -1812,6 +1811,7 @@ module_common_item: // ==IEEE: module_common_item | yALWAYS_FF event_controlE stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_FF, $2,$3); } | yALWAYS_LATCH event_controlE stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_LATCH, $2,$3); } | yALWAYS_COMB stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_COMB, NULL, $2); } + // | loop_generate_construct { $$ = $1; } | conditional_generate_construct { $$ = $1; } | elaboration_system_task { $$ = $1; } @@ -1820,8 +1820,7 @@ module_common_item: // ==IEEE: module_common_item ; continuous_assign: // IEEE: continuous_assign - yASSIGN delayE assignList ';' { $$ = $3; } - //UNSUP: strengthSpecE not in above assign + yASSIGN strengthSpecE delayE assignList ';' { $$ = $4; } ; initial_construct: // IEEE: initial_construct @@ -1837,6 +1836,7 @@ module_or_generate_item_declaration: // ==IEEE: module_or_generate_item_d | genvar_declaration { $$ = $1; } | clocking_declaration { $$ = $1; } | yDEFAULT yCLOCKING idAny/*new-clocking_identifier*/ ';' { $$ = NULL; BBUNSUP($1, "Unsupported: default clocking identifier"); } + //UNSUP yDEFAULT yDISABLE yIFF expr/*expression_or_dist*/ ';' { } ; aliasEqList: // IEEE: part of net_alias @@ -3229,6 +3229,7 @@ expr: // IEEE: part of expression/constant_expression/primary | ~l~expr yP_SLEFT ~r~expr { $$ = new AstShiftL ($2,$1,$3); } | ~l~expr yP_SRIGHT ~r~expr { $$ = new AstShiftR ($2,$1,$3); } | ~l~expr yP_SSRIGHT ~r~expr { $$ = new AstShiftRS ($2,$1,$3); } + | ~l~expr yP_LTMINUSGT ~r~expr { $$ = new AstLogEq ($2,$1,$3); } // // <= is special, as we need to disambiguate it with <= assignment // // We copy all of expr to fexpr and rename this token to a fake one. | ~l~expr yP_LTE~f__IGNORE~ ~r~expr { $$ = new AstLte ($2,$1,$3); } @@ -3246,7 +3247,6 @@ expr: // IEEE: part of expression/constant_expression/primary //======================// PSL expressions // | ~l~expr yP_MINUSGT ~r~expr { $$ = new AstLogIf ($2,$1,$3); } - | ~l~expr yP_LOGIFF ~r~expr { $$ = new AstLogIff ($2,$1,$3); } // //======================// IEEE: primary/constant_primary // @@ -3770,7 +3770,6 @@ variable_lvalue: // IEEE: variable_lvalue or net_lvalue //UNSUP data_type yP_TICKBRA variable_lvalueList '}' { UNSUP } //UNSUP idClassSel yP_TICKBRA variable_lvalueList '}' { UNSUP } //UNSUP /**/ yP_TICKBRA variable_lvalueList '}' { UNSUP } - //UNSUP streaming_concatenation { UNSUP } | streaming_concatenation { $$ = $1; } ; @@ -3954,12 +3953,18 @@ property_spec: // IEEE: property_spec | expr { $$ = new AstPslClocked($1->fileline(),NULL,NULL,$1); } ; +//************************************************ +// Let + //************************************************ // Covergroup //********************************************************************** // Randsequence +//********************************************************************** +// Checker + //********************************************************************** // Class @@ -4000,6 +4005,9 @@ package_scopeIdFollows: // IEEE: package_scope //UNSUP /*cont*/ yP_COLONCOLON { UNSUP } ; +//********************************************************************** +// Constraints + //********************************************************************** // VLT Files diff --git a/test_regress/t/t_math_arith.v b/test_regress/t/t_math_arith.v index b79aeea1a..b9287c67c 100644 --- a/test_regress/t/t_math_arith.v +++ b/test_regress/t/t_math_arith.v @@ -134,8 +134,18 @@ module t (/*AUTOARG*/ if (4'bz !== 4'bzzzz) $stop; if (4'b1 !== 4'b0001) $stop; - $write("*-* All Finished *-*\n"); - $finish; + if ((0 -> 0) != 1'b1) $stop; + if ((0 -> 1) != 1'b1) $stop; + if ((1 -> 0) != 1'b0) $stop; + if ((1 -> 1) != 1'b1) $stop; + + if ((0 <-> 0) != 1'b1) $stop; + if ((0 <-> 1) != 1'b0) $stop; + if ((1 <-> 0) != 1'b0) $stop; + if ((1 <-> 1) != 1'b1) $stop; + + $write("*-* All Finished *-*\n"); + $finish; end end