forked from github/verilator
Support logical equivalence operator <->.
This commit is contained in:
parent
902ba752a3
commit
f6f8073058
2
Changes
2
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]
|
||||
|
@ -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; }
|
||||
|
@ -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())");
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user