diff --git a/Changes b/Changes index 1cc24db0e..3919818de 100644 --- a/Changes +++ b/Changes @@ -13,6 +13,8 @@ indicates the contributor was also the author of the fix; Thanks! **** Fix internal error when public for loop has empty body. [David Addison] +**** Fix "Loops detected" assertion when model exceeds 4GB. [David Hewson] + * Verilator 3.633 2/7/2007 *** Add --trace-depth option for minimizing VCD file size. [Emerson Suguimoto] diff --git a/TODO b/TODO index 3f876af4e..f4532efc1 100644 --- a/TODO +++ b/TODO @@ -47,6 +47,10 @@ Testing: Better graph viewer with search and zoom Port and test against opencores.org code +Usability: + Better reporting of unopt problems, including what lines of code + Report more errors (all of them?) before exiting [Eugene Weber] + Performance: Constant propagation Extra cleaning AND: 1 & ((VARREF >> 1) | ((&VARREF >> 1) & VARREF)) diff --git a/nodist/dot_importer b/nodist/dot_importer new file mode 100755 index 000000000..f0f609bdc --- /dev/null +++ b/nodist/dot_importer @@ -0,0 +1,174 @@ +#!/usr/bin/perl -w +# $Id$ +###################################################################### +# +# Copyright 2005-2007 by Wilson Snyder . This +# program is free software; you can redistribute it and/or modify it under +# the terms of either the GNU Lesser General Public License or the Perl +# Artistic License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +###################################################################### + +require 5.006_001; +use Getopt::Long; +use IO::File; +use Pod::Usage; +use Data::Dumper; $Data::Dumper::Indent=1; +use strict; +use vars qw ($Debug); + +#====================================================================== + +our @Header; +our %Vertexes; +our @Edges; +our %Edges; + +#====================================================================== +# main + +$Debug = 0; +my $opt_filename; +autoflush STDOUT 1; +autoflush STDERR 1; +if (! GetOptions ( + "help" => \&usage, + "debug" => \&debug, + "<>" => \¶meter, + )) { + usage(); +} + +dotread ($opt_filename); +cwrite ("graph_export.cpp"); + +#---------------------------------------------------------------------- + +sub usage { + print '$Id$ ', "\n"; + pod2usage(-verbose=>2, -exitval => 2); + exit (1); +} + +sub debug { + $Debug = 1; +} + +sub parameter { + my $param = shift; + if (!$opt_filename) { + $opt_filename = $param; + } else { + die "%Error: Unknown parameter: $param\n"; + } +} + +####################################################################### + +sub dotread { + my $filename = shift; + + my $fh = IO::File->new($filename) or die "%Error: $! $filename,"; + my $header = 1; + my $vnum = 0; + while (defined (my $line = $fh->getline)) { + if ($line =~ /^\t([a-zA-Z0-9_]+)\t(.*)$/) { + next if $1 eq 'nTITLE'; + $header = 0; + $Vertexes{$1} = {num => $vnum++, + line => $line, + name => $1,}; + } + elsif ($line =~ /^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s+(.*)$/) { + my $from=$1; my $to=$2; + my $weight = 1; $weight = $1 if $line =~ /weight=(\d+)/; + my $cutable = undef; $cutable = $1 if $line =~ /style=(\S+)/; + my $edge = {num => $vnum++, + line => $line, + weight => $weight, + cutable => $cutable, + from => $from, + to => $to,}; + push @Edges, $edge; + $Edges{$from}{$to} = $edge; + } + elsif ($header) { + push @Header, $line; + print "IGNORE: $line"; + } + } +} + +####################################################################### + +sub cwrite { + my $filename = shift; + + my $fh = IO::File->new(">$filename") or die "%Error: $! $filename,"; + $fh->print("void V3GraphTestImport::dotImport() {\n"); + $fh->print(" DfaGraph* gp = &m_graph;\n"); + foreach my $ver (sort {$a->{num} <=> $b->{num}} (values %Vertexes)) { + $fh->printf(" V3GraphTestVertex* %s = new V3GraphTestVertex(gp, \"%s\"); if (%s) {}\n", + $ver->{name}, $ver->{name}, $ver->{name}); + } + $fh->print("\n"); + foreach my $edge (@Edges) { + $fh->printf(" new V3GraphEdge(gp, %s, %s, %s, %s);\n", + $edge->{from}, $edge->{to}, + $edge->{weight}, $edge->{cutable}?"true":"false"); + } + $fh->print("}\n"); +} + +####################################################################### +__END__ + +=pod + +=head1 NAME + +dot_importer - Take graph .dot file and convert into .cpp file + +=head1 SYNOPSIS + + dot_importer a.dot + +=head1 DESCRIPTION + +Dot_importer takes a graphvis .dot file and converts into .cpp file. This +.cpp file is then manually included in V3GraphTest.cpp to verify various +sub-algorithms. + +=head1 ARGUMENTS + +=over 4 + +=item --help + +Displays this message and program version and exits. + +=back + +=head1 DISTRIBUTION + +Copyright 2005-2007 by Wilson Snyder. This package is free software; you +can redistribute it and/or modify it under the terms of either the GNU +Lesser General Public License or the Perl Artistic License. + +=head1 AUTHORS + +Wilson Snyder + +=head1 SEE ALSO + +=cut + +###################################################################### +### Local Variables: +### compile-command: "./dot_importer | tee ~/d/a.dot" +### End: diff --git a/src/V3Graph.cpp b/src/V3Graph.cpp index 84b35b08c..720768dd8 100644 --- a/src/V3Graph.cpp +++ b/src/V3Graph.cpp @@ -180,6 +180,7 @@ void V3Graph::userClearVertices() { // the extra code on each read of user() would probably slow things down more then help. for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { vertexp->user(0); + vertexp->userp(NULL); // Its a union, but might be different size then user() } } @@ -187,7 +188,8 @@ void V3Graph::userClearEdges() { // Clear user() in all of tree for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { - edgep->userp(NULL); + edgep->user(0); + edgep->userp(NULL); // Its a union, but might be different size then user() } } } @@ -253,6 +255,8 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) { *logp<<"digraph v3graph {\n"; *logp<<"\trankdir="< SubgraphMmap; diff --git a/src/V3GraphAcyc.cpp b/src/V3GraphAcyc.cpp index 01c80082a..e5f7910f2 100644 --- a/src/V3GraphAcyc.cpp +++ b/src/V3GraphAcyc.cpp @@ -37,6 +37,7 @@ // Break the minimal number of backward edges to make the graph acyclic class GraphAcycVertex : public V3GraphVertex { + // user() is used for various sub-algorithm pieces V3GraphVertex* m_origVertexp; // Pointer to first vertex this represents protected: friend class GraphAcyc; @@ -308,6 +309,9 @@ void GraphAcyc::simplifyOne (GraphAcycVertex* avertexp) { avertexp->setDelete(); // Mark so we won't delete it twice // Make a new edge connecting the two vertices directly // If both are breakable, we pick the one with less weight, else it's arbitrary + // We can forget about the origEdge list for the "non-selected" set of edges, + // as we need to break only one set or the other set of edges, not both. + // (This is why we must give preference to the cutable set.) V3GraphEdge* templateEdgep = ( (inEdgep->cutable() && (!outEdgep->cutable() || inEdgep->weight()weight() )) @@ -353,7 +357,7 @@ void GraphAcyc::simplifyDup (GraphAcycVertex* avertexp) { if (avertexp->isDelete()) return; // Clear marks for (V3GraphEdge* edgep = avertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { - edgep->top()->user(false); + edgep->top()->userp(NULL); } // Mark edges and detect duplications for (V3GraphEdge* nextp, *edgep = avertexp->outBeginp(); edgep; edgep=nextp) { @@ -364,16 +368,16 @@ void GraphAcyc::simplifyDup (GraphAcycVertex* avertexp) { if (!prevEdgep->cutable()) { // !cutable duplicates prev !cutable: we can ignore it, redundant // cutable duplicates prev !cutable: know it's not a relevant loop, ignore it - UINFO(8," DelDupEdge "< "<top()<unlinkDelete(); edgep = NULL; } else if (!edgep->cutable()) { // !cutable duplicates prev cutable: delete the earlier cutable - UINFO(8," DelDupPrev "< "<top()<unlinkDelete(); prevEdgep = NULL; outVertexp->userp(edgep); } else { // cutable duplicates prev cutable: combine weights - UINFO(8," DelDupComb "< "<top()<weight (prevEdgep->weight() + edgep->weight()); addOrigEdgep (prevEdgep, edgep); edgep->unlinkDelete(); edgep = NULL; diff --git a/src/V3GraphTest.cpp b/src/V3GraphTest.cpp index faf2ae150..d150e1df0 100644 --- a/src/V3GraphTest.cpp +++ b/src/V3GraphTest.cpp @@ -311,6 +311,34 @@ public: gp->dfaReduce(); } }; + +//====================================================================== + +class V3GraphTestImport : public V3GraphTest { + + void dotImport(); + +public: + virtual string name() { return "import"; } + virtual void runTest() { + DfaGraph* gp = &m_graph; + if (V3GraphTest::debug()) gp->debug(9); + dotImport(); + dump(); + gp->acyclic(&V3GraphEdge::followAlwaysTrue); + dump(); + gp->rank(&V3GraphEdge::followAlwaysTrue); + dump(); + } +}; + +#if 0 +# include "graph_export.cpp" +#else +void V3GraphTestImport::dotImport() { +} +#endif + //====================================================================== void V3Graph::test() { @@ -320,5 +348,6 @@ void V3Graph::test() { { V3GraphTestAcyc test; test.run(); } { V3GraphTestVars test; test.run(); } { V3GraphTestDfa test; test.run(); } + { V3GraphTestImport test; test.run(); } if (V3GraphTest::debug()) v3fatalSrc("Exiting due to graph testing enabled"); } diff --git a/test_regress/t/t_EXAMPLE.v b/test_regress/t/t_EXAMPLE.v index c589baa89..6fc167f5e 100644 --- a/test_regress/t/t_EXAMPLE.v +++ b/test_regress/t/t_EXAMPLE.v @@ -7,59 +7,96 @@ // $finish // on success, or $stop. // +// The code as shown applies a random vector to the Test +// module, then calculates a CRC on the Test module's outputs. +// // **If you do not wish for your code to be released to the public -// please note it here** +// please note it here, otherwise:** +// +// 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; - // Some inputs we'll set to random values - reg [31:0] in_a; - reg [31:0] in_b; + integer cyc=0; + reg [63:0] crc; + reg [63:0] sum; - // Some arbitrary function for testing - // We'll test below that for each random in_a and in_b, we get a good out_a. - wire [31:0] out_x = (in_a ^ in_b); + // Take CRC data and apply to testblock inputs + wire [31:0] in = crc[31:0]; - integer cyc; initial cyc=1; + /*AUTOWIRE*/ + // Beginning of automatic wires (for undeclared instantiated-module outputs) + wire [31:0] out; // From test of Test.v + // End of automatics + + Test test (/*AUTOINST*/ + // Outputs + .out (out[31:0]), + // Inputs + .clk (clk), + .in (in[31:0])); + + // Aggregate outputs into a single result vector + wire [63:0] result = {32'h0, out}; + + // What checksum will we end up with +`define EXPECTED_SUM 64'h4afe43fb79d7b71e + + // Test loop always @ (posedge clk) begin - if (cyc!=0) begin - cyc <= cyc + 1; `ifdef TEST_VERBOSE - $write("%d %x %x %x\n", cyc, in_a, in_b, out_x); + $write("[%0t] cyc==%0d crc=%x result=%x\n",$time, cyc, crc, result); `endif - if (cyc==1) begin - // Assign inputs randomly - in_a <= 32'h89a14fab; - in_b <= 32'h7ab512fa; - end - if (cyc==2) begin - in_a <= 32'hf4c11a42; - in_b <= 32'h359967c6; - // Verify output is correct - if (out_x != 32'hf3145d51) $stop; - end - if (cyc==3) begin - in_a <= 32'h58dca151; - in_b <= 32'hdc687b27; - if (out_x != 32'hc1587d84) $stop; - end - if (cyc==4) begin - in_a <= 32'h09df0bbb; - in_b <= 32'h0d0e7231; - if (out_x != 32'h84b4da76) $stop; - end - if (cyc==5) begin - if (out_x != 32'h04d1798a) $stop; - end - if (cyc==9) begin - $write("*-* All Finished *-*\n"); - $finish; - end + 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 + ); + + // Replace this module with the device under test. + // + // Change the code in the t module to apply values to the inputs and + // merge the output values into the result vector. + + input clk; + input [31:0] in; + output [31:0] out; + + /*AUTOREG*/ + // Beginning of automatic regs (for this module's undeclared outputs) + reg [31:0] out; + // End of automatics + + always @(posedge clk) begin + out <= in; + end endmodule diff --git a/test_regress/t/t_func_endian.pl b/test_regress/t/t_func_endian.pl new file mode 100755 index 000000000..7bfdbe852 --- /dev/null +++ b/test_regress/t/t_func_endian.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_func_endian.v b/test_regress/t/t_func_endian.v new file mode 100644 index 000000000..606d480d4 --- /dev/null +++ b/test_regress/t/t_func_endian.v @@ -0,0 +1,110 @@ +// $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]; + wire noswap = crc[32]; + wire nibble = crc[33]; + + /*AUTOWIRE*/ + // Beginning of automatic wires (for undeclared instantiated-module outputs) + wire [31:0] out; // From test of Test.v + wire [31:0] swapped; // From test of Test.v + // End of automatics + + Test test (/*AUTOINST*/ + // Outputs + .out (out[31:0]), + .swapped (swapped[31:0]), + // Inputs + .clk (clk), + .noswap (noswap), + .nibble (nibble), + .in (in[31:0])); + + // Aggregate outputs into a single result vector + wire [63:0] result = {32'h0, out}; + + // 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("*-* All Finished *-*\n"); + $write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum); + if (crc !== 64'hc77bb9b3784ea091) $stop; + if (sum !== 64'h89522c3f5e5ca324) $stop; + $finish; + end + end + +endmodule + +module Test (/*AUTOARG*/ + // Outputs + out, swapped, + // Inputs + clk, noswap, nibble, in + ); + input clk; + + input noswap; + input nibble; + + input [31:0] in; + output [31:0] out; + output [31:0] swapped; + + function [7:0] EndianSwap; + input Nibble; + input [7:0] Data; + begin + EndianSwap = (Nibble ? { Data[0], Data[1], Data[2], Data[3], + Data[4], Data[5], Data[6], Data[7] } + : { 4'h0, Data[0], Data[1], Data[2], Data[3] }); + end + endfunction + + assign out[31:24] = (noswap ? in[31:24] + : EndianSwap(nibble, in[31:24])); + assign out[23:16] = (noswap ? in[23:16] + : EndianSwap(nibble, in[23:16])); + assign out[15:8] = (noswap ? in[15:8] + : EndianSwap(nibble, in[15:8])); + assign out[7:0] = (noswap ? in[7:0] + : EndianSwap(nibble, in[7:0])); + + reg [31:0] swapped; + always @(posedge clk) begin + swapped[31:24] <= EndianSwap(nibble, in[31:24]); + swapped[23:16] <= EndianSwap(nibble, in[23:16]); + swapped[15:8] <= EndianSwap(nibble, in[15:8] ); + swapped[7:0] <= EndianSwap(nibble, in[7:0] ); + end +endmodule