diff --git a/Changes b/Changes index 4e3e5a0c5..d5a9b154f 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,8 @@ indicates the contributor was also the author of the fix; Thanks! * Verilator 3.66*** +*** Add Verilog 2005 $clog2() function. + **** Add error message when modules have duplicate names. [Stefan Thiede] **** Allow defines terminated in EOF, though against spec. [Stefan Thiede] diff --git a/bin/verilator b/bin/verilator index 4a1bdfbc7..8fa60bbfa 100755 --- a/bin/verilator +++ b/bin/verilator @@ -1003,6 +1003,8 @@ declarations inside port lists. Verilator supports the `begin_keywords and `end_keywords compiler directives. +Verilator supports $clog2. + Verilator partially supports the uwire keyword. =head1 SYSTEMVERILOG (IEEE 1800-2005) SUPPORT diff --git a/include/verilated.h b/include/verilated.h index 5a6d95a70..a6f999f7c 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -495,6 +495,38 @@ static inline IData VL_REDXOR_64(QData r) { return r; } +static inline IData VL_CLOG2_I(IData lhs) { + // Perhaps can do better using fls GCC4 builtins + int n=1; + IData chk; + if (!lhs) return 0; + chk = lhs >> VL_UL(16); if (chk) { n += 16; lhs = chk; } + chk = lhs >> VL_UL(8); if (chk) { n += 8; lhs = chk; } + chk = lhs >> VL_UL(4); if (chk) { n += 4; lhs = chk; } + chk = lhs >> VL_UL(2); if (chk) { n += 2; lhs = chk; } + chk = lhs >> VL_UL(1); if (chk) { n += 1; lhs = chk; } + return n; +} +static inline IData VL_CLOG2_Q(QData lhs) { + // Perhaps can do better using fls GCC4 builtins + int n=1; + QData chk; + if (!lhs) return 0; + chk = lhs >> VL_ULL(32); if (chk) { n += 32; lhs = chk; } + chk = lhs >> VL_ULL(16); if (chk) { n += 16; lhs = chk; } + chk = lhs >> VL_ULL(8); if (chk) { n += 8; lhs = chk; } + chk = lhs >> VL_ULL(4); if (chk) { n += 4; lhs = chk; } + chk = lhs >> VL_ULL(2); if (chk) { n += 2; lhs = chk; } + chk = lhs >> VL_ULL(1); if (chk) { n += 1; lhs = chk; } + return n; +} +static inline IData VL_CLOG2_W(int words, WDataInP lwp) { + for (int i=words-1; i>=0; i--) { + if (lwp[i]) return VL_CLOG2_I(lwp[i])+i*VL_WORDSIZE; + } + return 0; +} + // EMIT_RULE: VL_COUNTONES_II: oclean = false; lhs clean static inline IData VL_COUNTONES_I(IData lhs) { IData r = lhs - ((lhs >> 1) & 033333333333) - ((lhs >> 2) & 011111111111); diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index e97cd232f..34dd06371 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -1971,6 +1971,20 @@ struct AstUnsigned : public AstNodeUniop { virtual bool sizeMattersLhs() {return true;} // Eliminated before matters virtual int instrCount() const { return 0; } }; +struct AstCLog2 : public AstNodeUniop { + AstCLog2(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {} + virtual ~AstCLog2() {} + virtual AstType type() const { return AstType::CLOG2;} + virtual AstNode* clone() { return new AstCLog2(*this); } + virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); } + virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opCLog2(lhs); } + virtual string emitVerilog() { return "%k$clog2(%l)"; } + virtual bool emitWordForm() { return true; } + virtual string emitOperator() { return "VL_CLOG2"; } + virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;} + virtual bool sizeMattersLhs() {return false;} + virtual int instrCount() const { return widthInstrs()*16; } +}; struct AstCountOnes : public AstNodeUniop { // Number of bits set in vector AstCountOnes(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {} diff --git a/src/V3Number.cpp b/src/V3Number.cpp index 466abb1c6..75a7653b8 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -259,6 +259,7 @@ V3Number::V3Number (FileLine* fileline, const char* sourcep) { // Global int V3Number::log2b(uint32_t num) { + // See also opCLog2 for (int bit=31; bit>0; bit--) if (num & (VL_ULL(1)<=0; bit--) { + if (lhs.bitIs1(bit)) { + setLong(bit+1); + return *this; + } + } + setZero(); + return *this; +} V3Number& V3Number::opLogNot (const V3Number& lhs) { // op i, 1 bit return diff --git a/src/V3Number.h b/src/V3Number.h index 8f28346ec..ffc27da5b 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -165,6 +165,7 @@ public: V3Number& opIsUnknown(const V3Number& lhs); V3Number& opOneHot (const V3Number& lhs); V3Number& opOneHot0 (const V3Number& lhs); + V3Number& opCLog2 (const V3Number& lhs); V3Number& opClean (const V3Number& lhs, uint32_t bits); V3Number& opConcat (const V3Number& lhs, const V3Number& rhs); V3Number& opRepl (const V3Number& lhs, const V3Number& rhs); diff --git a/src/V3Signed.cpp b/src/V3Signed.cpp index 9374ef442..645869130 100644 --- a/src/V3Signed.cpp +++ b/src/V3Signed.cpp @@ -70,6 +70,7 @@ private: virtual void visit(AstSel* nodep, AstNUser*) { signed_Ou_Ix(nodep); } //See backRequiresUnsigned virtual void visit(AstAttrOf* nodep, AstNUser*) { signed_Ou_Ix(nodep); } virtual void visit(AstCountOnes* nodep, AstNUser*) { signed_Ou_Ix(nodep); } + virtual void visit(AstCLog2* nodep, AstNUser*) { signed_Ou_Ix(nodep); } virtual void visit(AstPslBool* nodep, AstNUser*) { signed_Ou_Ix(nodep); } virtual void visit(AstTime* nodep, AstNUser*) { signed_Ou_Ix(nodep); } // diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 6e80879ae..87fb67668 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -378,6 +378,12 @@ private: // Just let all arguments seek their natural sizes nodep->iterateChildren(*this,WidthVP(ANYSIZE,0,BOTH).p()); } + virtual void visit(AstCLog2* nodep, AstNUser* vup) { + if (vup->c()->prelim()) { + nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); + nodep->width(32,32); + } + } virtual void visit(AstCountOnes* nodep, AstNUser* vup) { if (vup->c()->prelim()) { nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); diff --git a/src/verilog.l b/src/verilog.l index 59b930f84..b47965b83 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -313,6 +313,7 @@ escid \\[^ \t\f\r\n]+ { /* System Tasks */ "$bits" {yylval.fileline = CRELINE(); return yD_BITS;} + "$clog2" {yylval.fileline = CRELINE(); return yD_CLOG2;} "$countones" {yylval.fileline = CRELINE(); return yD_COUNTONES;} "$error" {yylval.fileline = CRELINE(); return yD_ERROR;} "$fatal" {yylval.fileline = CRELINE(); return yD_FATAL;} @@ -431,7 +432,7 @@ escid \\[^ \t\f\r\n]+ /* Default PLI rule */ { - "$"[a-zA-Z_$]+ {yyerrorf("Unsupported or unknown PLI call: %s",yytext);} + "$"[a-zA-Z_$][a-zA-Z0-9_$]* {yyerrorf("Unsupported or unknown PLI call: %s",yytext);} } /************************************************************************/ diff --git a/src/verilog.y b/src/verilog.y index d00ba1089..ffe977d58 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -220,6 +220,7 @@ class AstSenTree; %token yD_BITS "$bits" %token yD_C "$c" +%token yD_CLOG2 "$clog2" %token yD_COUNTONES "$countones" %token yD_DISPLAY "$display" %token yD_ERROR "$error" @@ -1072,6 +1073,7 @@ exprNoStr: expr yP_OROR expr { $$ = new AstLogOr ($2,$1,$3); } | yD_BITS '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::BITS,$3); } | yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? NULL : new AstUCFunc($1,$3)); } + | yD_CLOG2 '(' expr ')' { $$ = new AstCLog2($1,$3); } | yD_COUNTONES '(' expr ')' { $$ = new AstCountOnes($1,$3); } | yD_ISUNKNOWN '(' expr ')' { $$ = new AstIsUnknown($1,$3); } | yD_ONEHOT '(' expr ')' { $$ = new AstOneHot($1,$3); } diff --git a/test_regress/t/t_func_plog.v b/test_regress/t/t_func_plog.v index 1975cdb92..616ad559c 100644 --- a/test_regress/t/t_func_plog.v +++ b/test_regress/t/t_func_plog.v @@ -68,12 +68,12 @@ module t (/*AUTOARG*/ endmodule module Test - #(parameter SAMPLE_WIDTH = 4 ) + #(parameter SAMPLE_WIDTH = 5 ) ( `ifdef verilator // UNSUPPORTED - output reg [2:0] pos, + output reg [$clog2(SAMPLE_WIDTH-1)-1:0] pos, `else - output reg [log2(SAMPLE_WIDTH)-1:0] pos, + output reg [log2(SAMPLE_WIDTH-1)-1:0] pos, `endif // System input clk, diff --git a/test_regress/t/t_math_clog2.pl b/test_regress/t/t_math_clog2.pl new file mode 100755 index 000000000..7bfdbe852 --- /dev/null +++ b/test_regress/t/t_math_clog2.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_clog2.v b/test_regress/t/t_math_clog2.v new file mode 100644 index 000000000..2ce5dba94 --- /dev/null +++ b/test_regress/t/t_math_clog2.v @@ -0,0 +1,88 @@ +// $Id$ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2008 by Wilson Snyder. + +`ifdef verilator + `define CLOG2 $clog2 +`else + `define CLOG2 clog2_emulate +`endif + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc=0; + reg [63:0] crc; + reg [63:0] sum; + + wire [31:0] out = `CLOG2(crc[31:0]); + wire [31:0] out2 = `CLOG2(crc); + + // Aggregate outputs into a single result vector + wire [63:0] result = {out2, out}; + +`define EXPECTED_SUM 64'hc402f59e3d971718 + + // 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 + crc <= 64'h0; + if (`CLOG2(32'h0) != 0) $stop; + if (`CLOG2(32'h1) != 1) $stop; + if (`CLOG2(32'h7) != 3) $stop; + if (`CLOG2(32'h8) != 4) $stop; + if (`CLOG2(32'h9) != 4) $stop; + if (`CLOG2({32{1'b1}}) != 32) $stop; + if (`CLOG2({64{1'b1}}) != 64) $stop; + if (`CLOG2({128{1'b1}}) != 128) $stop; + end + else if (cyc==1) begin + crc <= 64'h1; + if (result != {32'd0, 32'd0}) $stop; + end + else if (cyc==2) begin + crc <= 64'h3; + if (result != {32'd1, 32'd1}) $stop; + end + else if (cyc==3) begin + crc <= {64{1'b1}}; + if (result != {32'd2, 32'd2}) $stop; + end + else if (cyc==4) begin + if (result != {32'd64, 32'd32}) $stop; + end + else if (cyc==8) begin + 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'hcbc77bb9b3784ea0) $stop; + if (sum !== `EXPECTED_SUM) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end + + function integer clog2_emulate(input [130:0] arg); + begin + for(clog2_emulate=0; arg>0; clog2_emulate=clog2_emulate+1) + arg = (arg >> 1); + end + endfunction +endmodule