From 5f6d69affd852aee5468892d7ae49ba1fe819647 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 18 Jul 2007 15:01:39 +0000 Subject: [PATCH] =?UTF-8?q?Support=20SystemVerilog=20=3D=3D=3F=20and=20!?= =?UTF-8?q?=3D=3F=20operators.?= git-svn-id: file://localhost/svn/verilator/trunk/verilator@945 77ca24e4-aefa-0310-84f0-b9a241c72d87 --- Changes | 4 ++ Makefile.in | 2 +- bin/verilator | 10 +++-- src/V3AstNodes.h | 33 +++++++++++++++ src/V3Const.cpp | 6 +++ src/V3Number.cpp | 22 ++++++++++ src/V3Number.h | 2 + src/V3Number_test.cpp | 3 ++ src/V3Signed.cpp | 2 + src/V3Unknown.cpp | 42 +++++++++++++++++++ src/V3Width.cpp | 2 + src/config_build.h.in | 2 +- src/verilog.l | 8 +++- src/verilog.y | 5 ++- test_regress/t/t_math_eq.pl | 18 +++++++++ test_regress/t/t_math_eq.v | 81 +++++++++++++++++++++++++++++++++++++ 16 files changed, 234 insertions(+), 8 deletions(-) create mode 100755 test_regress/t/t_math_eq.pl create mode 100644 test_regress/t/t_math_eq.v diff --git a/Changes b/Changes index 20839aa22..f6b8d1355 100644 --- a/Changes +++ b/Changes @@ -3,6 +3,10 @@ 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.65*** + +**** Support SystemVerilog ==? and !=? operators. + * Verilator 3.652 6/21/2007 **** Report as many warning types as possible before exiting. diff --git a/Makefile.in b/Makefile.in index 3fa13b2ab..6a0424143 100644 --- a/Makefile.in +++ b/Makefile.in @@ -4,7 +4,7 @@ # # This file is part of Verilator. # -# Author: Wilson Snyder or +# Author: Wilson Snyder # # Code available from: http://www.veripool.com/verilator # diff --git a/bin/verilator b/bin/verilator index 901561f24..e11fd8f4e 100755 --- a/bin/verilator +++ b/bin/verilator @@ -1010,12 +1010,14 @@ Verilator currently has very minimal support for SystemVerilog. As SystemVerilog features enter common usage they will be added. Contact the author if a feature you need is missing. -Verilator implements the full SystemVerilog 1800-2005 preprocessor subset, +Verilator implements the full SystemVerilog 1800-2005 preprocessor, including function call-like preprocessor defines. -Verilator supports $bits, $countones, $error, $fatal, $info, $isunknown, -$onehot, $onehot0, $warning, always_comb, always_ff, always_latch, -do-while, and final. It also supports .name and .* interconnection. +Verilator supports ==? and !=? operators, $bits, $countones, $error, +$fatal, $info, $isunknown, $onehot, $onehot0, $warning, always_comb, +always_ff, always_latch, do-while, and final. + +It also supports .name and .* interconnection. Verilator partially supports assert. diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 9cfa4e05a..fe8a9a854 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -2606,6 +2606,39 @@ struct AstNeqCase : public AstNodeBiCom { virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} }; +struct AstEqWild : public AstNodeBiop { + // Note wildcard operator rhs differs from lhs + AstEqWild(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { + width(1,1); } + virtual ~AstEqWild() {} + virtual AstType type() const { return AstType::EQWILD;} + virtual AstNode* clone() { return new AstEqWild(*this); } + virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opWildEq(lhs,rhs); } + virtual string emitVerilog() { return "%k(%l %k==? %r)"; } + virtual string emitOperator() { return "VL_EQ"; } // Until have 4 state anyways + virtual string emitSimpleOperator() { return "=="; } + virtual bool emitWordForm() { return true; } + virtual bool cleanOut() {return true;} + virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} + virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} +}; +struct AstNeqWild : public AstNodeBiop { + AstNeqWild(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { + width(1,1); } + virtual ~AstNeqWild() {} + virtual AstType type() const { return AstType::NEQWILD;} + virtual AstNode* clone() { return new AstNeqWild(*this); } + virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opWildNeq(lhs,rhs); } + virtual string emitVerilog() { return "%k(%l %k!=? %r)"; } + virtual string emitOperator() { return "VL_NEQ"; } // Until have 4 state anyways + virtual string emitSimpleOperator() { return "!="; } + virtual bool emitWordForm() { return true; } + virtual bool cleanOut() {return true;} + virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} + virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} +}; struct AstConcat : public AstNodeBiop { // If you're looking for {#{}}, see AstReplicate AstConcat(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { diff --git a/src/V3Const.cpp b/src/V3Const.cpp index d534d51b9..94d4848d3 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1110,6 +1110,10 @@ private: TREEOP ("AstLogNot{$lhsp.castEqCase}", "AstNeqCase{$lhsp->op1p(),$lhsp->op2p()}"); TREEOPV("AstNot {$lhsp.castNeqCase, $lhsp.width1}","AstEqCase {$lhsp->op1p(),$lhsp->op2p()}"); TREEOP ("AstLogNot{$lhsp.castNeqCase}", "AstEqCase {$lhsp->op1p(),$lhsp->op2p()}"); + TREEOPV("AstNot {$lhsp.castEqWild, $lhsp.width1}","AstNeqWild{$lhsp->op1p(),$lhsp->op2p()}"); + TREEOP ("AstLogNot{$lhsp.castEqWild}", "AstNeqWild{$lhsp->op1p(),$lhsp->op2p()}"); + TREEOPV("AstNot {$lhsp.castNeqWild, $lhsp.width1}","AstEqWild {$lhsp->op1p(),$lhsp->op2p()}"); + TREEOP ("AstLogNot{$lhsp.castNeqWild}", "AstEqWild {$lhsp->op1p(),$lhsp->op2p()}"); TREEOPV("AstNot {$lhsp.castEq, $lhsp.width1}", "AstNeq {$lhsp->op1p(),$lhsp->op2p()}"); TREEOP ("AstLogNot{$lhsp.castEq}", "AstNeq {$lhsp->op1p(),$lhsp->op2p()}"); TREEOPV("AstNot {$lhsp.castNeq, $lhsp.width1}", "AstEq {$lhsp->op1p(),$lhsp->op2p()}"); @@ -1151,6 +1155,7 @@ private: TREEOP("AstXor {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)"); TREEOP("AstEq {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); // We let X==X -> 1, although in a true 4-state sim it's X. TREEOP("AstEqCase {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); + TREEOP("AstEqWild {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); TREEOP("AstGt {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)"); TREEOP("AstGtS {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)"); TREEOP("AstGte {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); @@ -1161,6 +1166,7 @@ private: TREEOP("AstLteS {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); TREEOP("AstNeq {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)"); TREEOP("AstNeqCase{operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)"); + TREEOP("AstNeqWild{operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)"); TREEOP("AstLogAnd {operandsSame($lhsp,,$rhsp), $lhsp.width1}", "replaceWLhs(nodep)"); TREEOP("AstLogOr {operandsSame($lhsp,,$rhsp), $lhsp.width1}", "replaceWLhs(nodep)"); ///=== Verilog operators diff --git a/src/V3Number.cpp b/src/V3Number.cpp index 5333ded1f..78939f185 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -814,6 +814,28 @@ last: return setSingleBits(outc); } +V3Number& V3Number::opWildEq (const V3Number& lhs, const V3Number& rhs) { + char outc = 1; + for (int bit=0; bit=") gotnum.opGte (lhnum,rhnum); else if (op=="&&") gotnum.opLogAnd (lhnum,rhnum); diff --git a/src/V3Signed.cpp b/src/V3Signed.cpp index e9ba7b3b1..3ef919e83 100644 --- a/src/V3Signed.cpp +++ b/src/V3Signed.cpp @@ -98,8 +98,10 @@ private: // ... (Though they should match. We don't check.) virtual void visit(AstEq* nodep, AstNUser*) { signed_Ou_Ix(nodep); } virtual void visit(AstEqCase* nodep, AstNUser*) { signed_Ou_Ix(nodep); } + virtual void visit(AstEqWild* nodep, AstNUser*) { signed_Ou_Ix(nodep); } virtual void visit(AstNeq* nodep, AstNUser*) { signed_Ou_Ix(nodep); } virtual void visit(AstNeqCase* nodep, AstNUser*){ signed_Ou_Ix(nodep); } + virtual void visit(AstNeqWild* nodep, AstNUser*){ signed_Ou_Ix(nodep); } //======= // Signed: Output signed iff LHS signed; unary operator diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp index 023da7ba2..f2c2810f2 100644 --- a/src/V3Unknown.cpp +++ b/src/V3Unknown.cpp @@ -106,6 +106,42 @@ private: newp->iterateChildren(*this); } } + void visitEqNeqWild(AstNodeBiop* nodep) { + UINFO(4," N/EQWILD->EQ "<lhsp()); + V3Const::constifyTree(nodep->rhsp()); + if (nodep->lhsp()->castConst() && nodep->rhsp()->castConst()) { + // Both sides are constant, node can be constant + V3Const::constifyTree(nodep); nodep=NULL; + return; + } else { + AstNode* lhsp = nodep->lhsp()->unlinkFrBack(); + AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); + AstNode* newp; + if (!rhsp->castConst()) { + nodep->v3error("Unsupported: RHS of ==? or !=? must be constant to be synthesizable"); // Says spec. + // Replace with anything that won't cause more errors + newp = new AstEq (nodep->fileline(), lhsp, rhsp); + } else { + // X or Z's become mask, ala case statements. + V3Number nummask (rhsp->fileline(), rhsp->width()); + nummask.opBitsNonX(rhsp->castConst()->num()); + V3Number numval (rhsp->fileline(), rhsp->width()); + numval.opBitsOne (rhsp->castConst()->num()); + AstNode* and1p = new AstAnd(nodep->fileline(), lhsp, + new AstConst(nodep->fileline(), nummask)); + AstNode* and2p = new AstConst(nodep->fileline(), numval); + if (nodep->castEqWild()) + newp = new AstEq (nodep->fileline(), and1p, and2p); + else newp = new AstNeq (nodep->fileline(), and1p, and2p); + rhsp->deleteTree(); rhsp=NULL; + } + nodep->replaceWith(newp); + nodep->deleteTree(); nodep=NULL; + // Iterate tree now that we may have gotten rid of the compare + newp->iterateChildren(*this); + } + } virtual void visit(AstEqCase* nodep, AstNUser*) { visitEqNeqCase(nodep); @@ -113,6 +149,12 @@ private: virtual void visit(AstNeqCase* nodep, AstNUser*) { visitEqNeqCase(nodep); } + virtual void visit(AstEqWild* nodep, AstNUser*) { + visitEqNeqWild(nodep); + } + virtual void visit(AstNeqWild* nodep, AstNUser*) { + visitEqNeqWild(nodep); + } virtual void visit(AstIsUnknown* nodep, AstNUser*) { nodep->iterateChildren(*this); // Ahh, we're two state, so this is easy diff --git a/src/V3Width.cpp b/src/V3Width.cpp index fa8f828a8..5ccd62e3b 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -117,6 +117,7 @@ private: void width_O1_L_Rlhs(AstNode* nodep, AstNUser* vup); virtual void visit(AstEq* nodep, AstNUser* vup) { width_O1_L_Rlhs(nodep,vup); } virtual void visit(AstEqCase* nodep, AstNUser* vup) { width_O1_L_Rlhs(nodep,vup); } + virtual void visit(AstEqWild* nodep, AstNUser* vup) { width_O1_L_Rlhs(nodep,vup); } virtual void visit(AstGt* nodep, AstNUser* vup) { width_O1_L_Rlhs(nodep,vup); } virtual void visit(AstGtS* nodep, AstNUser* vup) { width_O1_L_Rlhs(nodep,vup); } virtual void visit(AstGte* nodep, AstNUser* vup) { width_O1_L_Rlhs(nodep,vup); } @@ -127,6 +128,7 @@ private: virtual void visit(AstLteS* nodep, AstNUser* vup) { width_O1_L_Rlhs(nodep,vup); } virtual void visit(AstNeq* nodep, AstNUser* vup) { width_O1_L_Rlhs(nodep,vup); } virtual void visit(AstNeqCase* nodep, AstNUser* vup){ width_O1_L_Rlhs(nodep,vup); } + virtual void visit(AstNeqWild* nodep, AstNUser* vup){ width_O1_L_Rlhs(nodep,vup); } // Widths: out width = lhs width = rhs width void width_Omax_L_Rlhs(AstNode* nodep, AstNUser* vup); diff --git a/src/config_build.h.in b/src/config_build.h.in index ce67baec1..768450845 100644 --- a/src/config_build.h.in +++ b/src/config_build.h.in @@ -4,7 +4,7 @@ // // This file is part of Verilator. // -// Author: Wilson Snyder or +// Author: Wilson Snyder // // Code available from: http://www.veripool.com/verilator // diff --git a/src/verilog.l b/src/verilog.l index 7428b659e..085edd87d 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -578,6 +578,12 @@ escid \\[^ \t\f\r\n]+ "-:" {yylval.fileline = CRELINE(); return yP_MINUSCOLON;} } + /* SystemVerilog Operators */ +{ + "==?" {yylval.fileline = CRELINE(); return yP_WILDEQUAL;} + "!=?" {yylval.fileline = CRELINE(); return yP_WILDNOTEQUAL;} +} + /* PSL Operators */ { "{" {yylval.fileline = CRELINE(); return yPSL_BRA;} // Avoid parser hitting concatenate. @@ -659,7 +665,7 @@ escid \\[^ \t\f\r\n]+ "*)" { yy_pop_state(); } . { yymore(); } <> { yyerror("EOF in (*"); - yyleng = 0; } + yyleng = 0; yy_pop_state(); } /************************************************************************/ /* Attributes */ diff --git a/src/verilog.y b/src/verilog.y index b75ce6678..8bbcee967 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -269,7 +269,7 @@ class AstSenTree; %left '^' %left yP_XNOR %left '&' yP_NAND -%left yP_EQUAL yP_NOTEQUAL yP_CASEEQUAL yP_CASENOTEQUAL +%left yP_EQUAL yP_NOTEQUAL yP_CASEEQUAL yP_CASENOTEQUAL yP_WILDEQUAL yP_WILDNOTEQUAL %left '>' '<' yP_GTE yP_LTE %left yP_SLEFT yP_SRIGHT yP_SSRIGHT %left '+' '-' @@ -912,6 +912,8 @@ exprNoStr: expr yP_OROR expr { $$ = new AstLogOr ($2,$1,$3); } | expr yP_NOTEQUAL expr { $$ = new AstNeq ($2,$1,$3); } | expr yP_CASEEQUAL expr { $$ = new AstEqCase ($2,$1,$3); } | expr yP_CASENOTEQUAL expr { $$ = new AstNeqCase ($2,$1,$3); } + | expr yP_WILDEQUAL expr { $$ = new AstEqWild ($2,$1,$3); } + | expr yP_WILDNOTEQUAL expr { $$ = new AstNeqWild ($2,$1,$3); } | expr '>' expr { $$ = new AstGt ($2,$1,$3); } | expr '<' expr { $$ = new AstLt ($2,$1,$3); } | expr yP_GTE expr { $$ = new AstGte ($2,$1,$3); } @@ -1104,6 +1106,7 @@ specifyJunk: dlyTerm {} /* ignored */ | yP_ANDAND {} | yP_GTE {} | yP_LTE {} | yP_EQUAL {} | yP_NOTEQUAL {} | yP_CASEEQUAL {} | yP_CASENOTEQUAL {} + | yP_WILDEQUAL {} | yP_WILDNOTEQUAL {} | yP_XNOR {} | yP_NOR {} | yP_NAND {} | yP_OROR {} | yP_SLEFT {} | yP_SRIGHT {} | yP_SSRIGHT {} diff --git a/test_regress/t/t_math_eq.pl b/test_regress/t/t_math_eq.pl new file mode 100755 index 000000000..7bfdbe852 --- /dev/null +++ b/test_regress/t/t_math_eq.pl @@ -0,0 +1,18 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; } +# $Id$ +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# General Public License or the Perl Artistic License. + +compile ( + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_math_eq.v b/test_regress/t/t_math_eq.v new file mode 100644 index 000000000..4f9d16c88 --- /dev/null +++ b/test_regress/t/t_math_eq.v @@ -0,0 +1,81 @@ +// $Id$ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2007 by Wilson Snyder. + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc=0; + reg [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 [3:0] out; // From test of Test.v + // End of automatics + + Test test (/*AUTOINST*/ + // Outputs + .out (out[3:0]), + // Inputs + .clk (clk), + .in (in[31:0])); + + // Aggregate outputs into a single result vector + wire [63:0] result = {60'h0, out}; + + // What checksum will we end up with +`define EXPECTED_SUM 64'h1a0d07009b6a30d2 + + // 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; + 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; + 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 [3:0] out; + + assign out[0] = in[3:0] ==? 4'b1001; + assign out[1] = in[3:0] !=? 4'b1001; + assign out[2] = in[3:0] ==? 4'bx01x; + assign out[3] = in[3:0] !=? 4'bx01x; +endmodule