Support logical equivalence operator <->.

This commit is contained in:
Wilson Snyder 2019-06-01 19:40:06 -04:00
parent 902ba752a3
commit f6f8073058
9 changed files with 86 additions and 37 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -843,6 +843,11 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"["{ws}*"->" { FL; return yP_BRAMINUSGT; }
}
/* SystemVerilog 2009 Operators */
<S09,S12,S17,SAX,VLT>{
"<->" { FL; return yP_LTMINUSGT; }
}
/* Identifiers and numbers */
<V95,V01,V05,VA5,S05,S09,S12,S17,SAX,VLT>{
{escid} { FL; yylval.strp = PARSEP->newString

View File

@ -587,6 +587,7 @@ class AstSenTree;
%token<fl> yP_PAR__STRENGTH "(-for-strength"
%token<fl> yP_LTMINUSGT "<->"
%token<fl> yP_PLUSCOLON "+:"
%token<fl> yP_MINUSCOLON "-:"
%token<fl> yP_MINUSGT "->"
@ -621,8 +622,6 @@ class AstSenTree;
%token<fl> yP_SRIGHTEQ ">>="
%token<fl> yP_SSRIGHTEQ ">>>="
%token<fl> 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<nodep>: // ==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<nodep>: // ==IEEE: module_common_item
;
continuous_assign<nodep>: // IEEE: continuous_assign
yASSIGN delayE assignList ';' { $$ = $3; }
//UNSUP: strengthSpecE not in above assign
yASSIGN strengthSpecE delayE assignList ';' { $$ = $4; }
;
initial_construct<nodep>: // IEEE: initial_construct
@ -1837,6 +1836,7 @@ module_or_generate_item_declaration<nodep>: // ==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<nodep>: // 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<nodep>: // 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<nodep>: // 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<nodep>: // IEEE: property_spec
| expr { $$ = new AstPslClocked($1->fileline(),NULL,NULL,$1); }
;
//************************************************
// Let
//************************************************
// Covergroup
//**********************************************************************
// Randsequence
//**********************************************************************
// Checker
//**********************************************************************
// Class
@ -4000,6 +4005,9 @@ package_scopeIdFollows<packagep>: // IEEE: package_scope
//UNSUP /*cont*/ yP_COLONCOLON { UNSUP }
;
//**********************************************************************
// Constraints
//**********************************************************************
// VLT Files

View File

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