diff --git a/Changes b/Changes index 491b184a6..177919ff7 100644 --- a/Changes +++ b/Changes @@ -7,6 +7,8 @@ indicates the contributor was also the author of the fix; Thanks! *** Optimize two-level shift and and/or trees, +23% on one test. +**** Support posedge of bit-selected signals, bug45. [Rodney Sinclair] + **** Fix arrayed variables under function not compiling, bug44. [Ralf Karge] **** Fix --output-split-cfuncs to also split trace code. [Niranjan Prabhu] diff --git a/bin/verilator b/bin/verilator index 3fc3e5d85..3c00d8430 100755 --- a/bin/verilator +++ b/bin/verilator @@ -241,7 +241,7 @@ descriptions in the next sections for more information. Specifies the Verilog file containing the top module to be Verilated. -=item {file.c/cc/cpp} +=item {file.c/.cc/.cpp/.cxx} Specifies optional C++ files to be linked in with the Verilog code. If any C++ files are specified in this way, Verilator will include a make rule diff --git a/src/V3Active.cpp b/src/V3Active.cpp index 12178a06c..28e7e87e4 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -278,8 +278,9 @@ private: // We'll add it as a generic COMBO SenItem in a moment. itemp->unlinkFrBack()->deleteTree(); itemp=NULL; senp=NULL; } else if (itemp->varrefp()) { + // V3LinkResolve should have cleaned most of these up if (itemp->varrefp()->width()>1) itemp->v3error("Unsupported: Non-single bit wide signal pos/negedge sensitivity: " - <varrefp()->prettyName()); + <varrefp()->prettyName()); sequent = true; itemp->varrefp()->varp()->usedClock(true); } diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index a81fd9aa2..204fe5bf1 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -25,6 +25,7 @@ // Add SUB so that we subtract off the "base 0-start" of the array // File operations // Convert normal var to FILE* type +// SenItems: Convert pos/negedge of non-simple signals to temporaries //************************************************************************* #include "config_build.h" @@ -55,6 +56,7 @@ private: AstModule* m_modp; // Current module AstNodeFTask* m_ftaskp; // Function or task we're inside AstVAssert* m_assertp; // Current assertion + int m_senitemCvtNum; // Temporary signal counter //int debug() { return 9; } @@ -64,6 +66,7 @@ private: // Module: Create sim table for entire module and iterate UINFO(8,"MODULE "<iterateChildren(*this); m_modp = NULL; } @@ -105,19 +108,53 @@ private: virtual void visit(AstSenItem* nodep, AstNUser*) { // Remove bit selects, and bark if it's not a simple variable nodep->iterateChildren(*this); - bool did=1; - while (did) { - did=0; - if (AstNodeSel* selp = nodep->sensp()->castNodeSel()) { - AstNode* fromp = selp->fromp()->unlinkFrBack(); - selp->replaceWith(fromp); selp->deleteTree(); selp=NULL; - did=1; + if (nodep->isClocked()) { + // If it's not a simple variable wrap in a temporary + // This is a bit unfortunate as we haven't done width resolution + // and any width errors will look a bit odd, but it works. + AstNode* sensp = nodep->sensp(); + if (sensp + && !sensp->castNodeVarRef() + && !sensp->castConst()) { + // Make a new temp wire + string newvarname = "__Vsenitemexpr"+cvtToStr(++m_senitemCvtNum); + AstVar* newvarp = new AstVar (sensp->fileline(), AstVarType::MODULETEMP, newvarname, + NULL,NULL); + // We can't just add under the module, because we may be inside a generate, begin, etc. + // We know a SenItem should be under a SenTree/Always etc, we we'll just hunt upwards + AstNode* addwherep = nodep; // Add to this element's next + while (addwherep->castSenItem() + || addwherep->castSenTree()) { + addwherep = addwherep->backp(); + } + if (!addwherep->castAlways()) { // Assertion perhaps? + sensp->v3error("Unsupported: Non-single-bit pos/negedge clock statement under some complicated block"); + addwherep = m_modp; + } + addwherep->addNext(newvarp); + + sensp->replaceWith(new AstVarRef (sensp->fileline(), newvarp, false)); + AstAssignW* assignp = new AstAssignW + (sensp->fileline(), + new AstVarRef(sensp->fileline(), newvarp, true), + sensp); + addwherep->addNext(assignp); } - // NodeSel doesn't include AstSel.... - if (AstSel* selp = nodep->sensp()->castSel()) { - AstNode* fromp = selp->fromp()->unlinkFrBack(); - selp->replaceWith(fromp); selp->deleteTree(); selp=NULL; - did=1; + } else { // Old V1995 sensitivity list; we'll probably mostly ignore + bool did=1; + while (did) { + did=0; + if (AstNodeSel* selp = nodep->sensp()->castNodeSel()) { + AstNode* fromp = selp->fromp()->unlinkFrBack(); + selp->replaceWith(fromp); selp->deleteTree(); selp=NULL; + did=1; + } + // NodeSel doesn't include AstSel.... + if (AstSel* selp = nodep->sensp()->castSel()) { + AstNode* fromp = selp->fromp()->unlinkFrBack(); + selp->replaceWith(fromp); selp->deleteTree(); selp=NULL; + did=1; + } } } if (!nodep->sensp()->castNodeVarRef()) { @@ -428,6 +465,7 @@ public: m_ftaskp = NULL; m_modp = NULL; m_assertp = NULL; + m_senitemCvtNum = 0; // rootp->accept(*this); } diff --git a/test_regress/t/t_clk_vecgen1.pl b/test_regress/t/t_clk_vecgen1.pl new file mode 100755 index 000000000..8d9b04936 --- /dev/null +++ b/test_regress/t/t_clk_vecgen1.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# 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. + +top_filename("t/t_clk_vecgen1.v"); + +compile ( + v_flags2 => ['+define+T_TEST1',], + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_clk_vecgen1.v b/test_regress/t/t_clk_vecgen1.v new file mode 100644 index 000000000..089fee0da --- /dev/null +++ b/test_regress/t/t_clk_vecgen1.v @@ -0,0 +1,123 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2008 by Wilson Snyder. + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc=0; + reg [63:0] crc; + reg [63:0] sum; + + wire [1:0] clkvec = crc[1:0]; + + /*AUTOWIRE*/ + // Beginning of automatic wires (for undeclared instantiated-module outputs) + wire [1:0] count; // From test of Test.v + // End of automatics + + Test test (/*AUTOINST*/ + // Outputs + .count (count[1:0]), + // Inputs + .clkvec (clkvec[1:0])); + + // Aggregate outputs into a single result vector + wire [63:0] result = {62'h0, count}; + + // 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; +`define EXPECTED_SUM 64'hfe8bac0bb1a0e53b + if (sum !== `EXPECTED_SUM) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + +`ifdef T_TEST1 +module Test + ( + input wire [1:0] clkvec, + // verilator lint_off MULTIDRIVEN + output reg [1:0] count + // verilator lint_on MULTIDRIVEN + ); + genvar igen; + generate + for (igen=0; igen<2; igen=igen+1) begin : code_gen + initial count[igen] = 1'b0; + always @ (posedge clkvec[igen]) + count[igen] <= count[igen] + 1; + end + endgenerate + always @ (count) begin + $write("hi\n"); + end +endmodule +`endif + +`ifdef T_TEST2 +module Test + ( + input wire [1:0] clkvec, + // verilator lint_off MULTIDRIVEN + output reg [1:0] count + // verilator lint_on MULTIDRIVEN + ); + genvar igen; + generate + for (igen=0; igen<2; igen=igen+1) begin : code_gen + wire clk_tmp = clkvec[igen]; + // Unsupported: Count is multidriven, though if we did better analysis it wouldn't + // need to be. + initial count[igen] = 1'b0; + always @ (posedge clk_tmp) + count[igen] <= count[igen] + 1; + end + endgenerate +endmodule +`endif + +`ifdef T_TEST3 +module Test + ( + input wire [1:0] clkvec, + output wire [1:0] count + ); + genvar igen; + generate + for (igen=0; igen<2; igen=igen+1) begin : code_gen + wire clk_tmp = clkvec[igen]; + reg tmp_count = 1'b0; + always @ (posedge clk_tmp) begin + tmp_count <= tmp_count + 1; + end + assign count[igen] = tmp_count; + end + endgenerate +endmodule +`endif diff --git a/test_regress/t/t_clk_vecgen2.pl b/test_regress/t/t_clk_vecgen2.pl new file mode 100755 index 000000000..632e0ec4d --- /dev/null +++ b/test_regress/t/t_clk_vecgen2.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# 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. + +top_filename("t/t_clk_vecgen1.v"); + +compile ( + v_flags2 => ['+define+T_TEST2',], + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_clk_vecgen3.pl b/test_regress/t/t_clk_vecgen3.pl new file mode 100755 index 000000000..15d4a5192 --- /dev/null +++ b/test_regress/t/t_clk_vecgen3.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# 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. + +top_filename("t/t_clk_vecgen1.v"); + +compile ( + v_flags2 => ['+define+T_TEST3',], + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1;