diff --git a/Changes b/Changes index 386df678c..ed008683b 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,8 @@ The contributors that suggested a given feature are shown in []. Thanks! * Verilator 3.903 devel +*** Fix non-cutable ordering loops on clock arrays, bug1009. [Todd Strader] + *** Support ports of array of reals, bug1154. [J Briquet] *** Support arrayed parameter overrides, bug1153. [John Stevenson] diff --git a/bin/verilator b/bin/verilator index dd4a40941..211c109bd 100755 --- a/bin/verilator +++ b/bin/verilator @@ -495,6 +495,10 @@ If the signal is the input to top-module, the directly the signal name. If you find it difficult to find the exact name, try to use C in RTL file to mark the signal directly. +If clock signals are assigned to vectors and then later used individually, +Verilator will attempt to decompose the vector and connect the single-bit +clock signals directly. This should be transparent to the user. + =item --compiler I Enables tunings and workarounds for the specified C++ compiler. diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 124cdb5b5..7d497113c 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -113,6 +113,20 @@ public: } return ret; } + // Returns only the result from the LAST vertex iterated over + // Note: This behaves differently than iterateInEdges() in that it will traverse + // all edges that exist when it is initially called, whereas + // iterateInEdges() will stop traversing edges if one is deleted + VNUser iterateCurrentOutEdges(GateGraphBaseVisitor& v, VNUser vu=VNUser(0)) { + VNUser ret = VNUser(0); + V3GraphEdge* next_edgep = NULL; + for (V3GraphEdge* edgep = outBeginp(); edgep; edgep = next_edgep) { + // Need to find the next edge before visiting in case the edge is deleted + next_edgep = edgep->outNextp(); + ret = dynamic_cast(edgep->top())->accept(v, vu); + } + return ret; + } }; class GateVarVertex : public GateEitherVertex { @@ -291,6 +305,7 @@ private: // {statement}Node::user1p -> GateLogicVertex* for this statement // AstVarScope::user2 -> bool: Signal used in SenItem in *this* always statement // AstVar::user2 -> bool: Warned about SYNCASYNCNET + // AstVarNodeRef::user2 -> bool: ConcatOffset visited AstUser1InUse m_inuser1; AstUser2InUse m_inuser2; @@ -358,6 +373,7 @@ private: void replaceAssigns(); void dedupe(); void mergeAssigns(); + void decomposeClkVectors(); // VISITORS virtual void visit(AstNetlist* nodep) { @@ -365,6 +381,8 @@ private: //if (debug()>6) m_graph.dump(); if (debug()>6) m_graph.dumpDotFilePrefixed("gate_pre"); warnSignals(); // Before loss of sync/async pointers + // Decompose clock vectors -- need to do this before removing redundant edges + decomposeClkVectors(); m_graph.removeRedundantEdgesSum(&V3GraphEdge::followAlwaysTrue); m_graph.dumpDotFilePrefixed("gate_simp"); // Find gate interconnect and optimize @@ -1238,6 +1256,200 @@ void GateVisitor::mergeAssigns() { m_statAssignMerged += merger.numMergedAssigns(); } +//###################################################################### +// Find a var's offset in a concatenation + +class GateConcatVisitor : public GateBaseVisitor { +private: + // STATE + AstVarScope* m_vscp; // Varscope we're trying to find + int m_offset; // Current offset of varscope + int m_found_offset; // Found offset of varscope + bool m_found; // Offset found + + // VISITORS + virtual void visit(AstNodeVarRef* nodep) { + UINFO(9,"CLK DECOMP Concat search var (off = "<varScopep() == m_vscp && !nodep->user2() && !m_found) { + // A concatenation may use the same var multiple times + // But the graph will initially have an edge per instance + nodep->user2(true); + m_found_offset = m_offset; + m_found = true; + UINFO(9,"CLK DECOMP Concat found var (off = "<dtypep()->width(); + } + virtual void visit(AstConcat* nodep) { + UINFO(9,"CLK DECOMP Concat search (off = "<rhsp()->iterate(*this); + nodep->lhsp()->iterate(*this); + } + //-------------------- + // Default + virtual void visit(AstNode* nodep) { + nodep->iterateChildren(*this); + } +public: + // CONSTUCTORS + GateConcatVisitor() { + m_vscp = NULL; + m_offset = 0; + m_found_offset = 0; + m_found = false; + } + virtual ~GateConcatVisitor() {} + // PUBLIC METHODS + bool concatOffset(AstConcat* concatp, AstVarScope* vscp, int& offsetr) { + m_vscp = vscp; + m_offset = 0; + m_found = false; + // Iterate + concatp->accept(*this); + UINFO(9,"CLK DECOMP Concat Offset (found = "< bool: already visited + V3Graph* m_graphp; + int m_seen_clk_vectors; + AstVarScope* m_clk_vsp; + GateVarVertex* m_clk_vvertexp; + GateConcatVisitor m_concat_visitor; + int m_total_seen_clk_vectors; + int m_total_decomposed_clk_vectors; + + virtual VNUser visit(GateVarVertex* vvertexp, VNUser vu) { + // Check that we haven't been here before + AstVarScope* vsp = vvertexp->varScp(); + if (vsp->user2SetOnce()) return VNUser(0); + UINFO(9,"CLK DECOMP Var - "<varp()->width() > 1) { + m_seen_clk_vectors++; + m_total_seen_clk_vectors++; + } + GateClkDecompState* currState = (GateClkDecompState*) vu.c(); + GateClkDecompState nextState(currState->m_offset, vsp); + vvertexp->iterateCurrentOutEdges(*this, VNUser(&nextState)); + if (vsp->varp()->width() > 1) { + m_seen_clk_vectors--; + } + vsp->user2(false); + return VNUser(0); + } + + virtual VNUser visit(GateLogicVertex* lvertexp, VNUser vu) { + GateClkDecompState* currState = (GateClkDecompState*) vu.c(); + int clk_offset = currState->m_offset; + if (AstAssignW* assignp = lvertexp->nodep()->castAssignW()) { + UINFO(9,"CLK DECOMP Logic (off = "<rhsp()->castSel()) { + if (rselp->lsbp()->castConst() && rselp->widthp()->castConst()) { + if (clk_offset < rselp->lsbConst() || clk_offset > rselp->msbConst()) { + UINFO(9,"CLK DECOMP Sel [ "<msbConst()<<" : "<lsbConst()<<" ] dropped clock ("<lsbConst(); + } else { + return VNUser(0); + } + } else if (AstConcat* catp = assignp->rhsp()->castConcat()) { + UINFO(9,"CLK DECOMP Concat searching - "<lhsp()<m_last_vsp, concat_offset)) { + return VNUser(0); + } + clk_offset += concat_offset; + } + if (AstSel* lselp = assignp->lhsp()->castSel()) { + if (lselp->lsbp()->castConst() && lselp->widthp()->castConst()) { + clk_offset += lselp->lsbConst(); + } else { + return VNUser(0); + } + } else if (AstVarRef* vrp = assignp->lhsp()->castVarRef()) { + if (vrp->dtypep()->width() == 1 && m_seen_clk_vectors) { + if (clk_offset != 0) { + UINFO(9,"Should only make it here with clk_offset = 0"<lhsp()<<" <-> "<rhsp(); + rhsp->replaceWith(new AstVarRef(rhsp->fileline(), m_clk_vsp, false)); + for (V3GraphEdge* edgep = lvertexp->inBeginp(); edgep; ) { + edgep->unlinkDelete(); VL_DANGLING(edgep); + } + new V3GraphEdge(m_graphp, m_clk_vvertexp, lvertexp, 1); + m_total_decomposed_clk_vectors++; + } + } + GateClkDecompState nextState(clk_offset, currState->m_last_vsp); + return lvertexp->iterateCurrentOutEdges(*this, VNUser(&nextState)); + } + return VNUser(0); + } + +public: + GateClkDecompGraphVisitor(V3Graph* graphp) { + m_graphp = graphp; + m_seen_clk_vectors = 0; + m_clk_vsp = NULL; + m_clk_vvertexp = NULL; + m_total_seen_clk_vectors = 0; + m_total_decomposed_clk_vectors = 0; + } + virtual ~GateClkDecompGraphVisitor() { + V3Stats::addStat("Optimizations, Clocker seen vectors", m_total_seen_clk_vectors); + V3Stats::addStat("Optimizations, Clocker decomposed vectors", m_total_decomposed_clk_vectors); + } + void clkDecomp(GateVarVertex* vvertexp) { + UINFO(9,"CLK DECOMP Starting Var - "<varScp(); + m_clk_vvertexp = vvertexp; + GateClkDecompState nextState(0, m_clk_vsp); + vvertexp->accept(*this, VNUser(&nextState)); + } +}; + +void GateVisitor::decomposeClkVectors() { + UINFO(9,"Starting clock decomposition"<verticesNextp()) { + if (GateVarVertex* vertp = dynamic_cast(itp)) { + AstVarScope* vsp = vertp->varScp(); + if (vsp->varp()->attrClocker() == AstVarAttrClocker::CLOCKER_YES) { + if (vsp->varp()->width() > 1) { + UINFO(9,"Clocker > 1 bit, not decomposing: "<1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_clk_concat.v b/test_regress/t/t_clk_concat.v new file mode 100644 index 000000000..caba2a926 --- /dev/null +++ b/test_regress/t/t_clk_concat.v @@ -0,0 +1,97 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty. +// + +module some_module ( + input wrclk + ); + + logic [ 1 : 0 ] some_state; + logic [1:0] some_other_state; + + always @(posedge wrclk) begin + case (some_state) + 2'b11: + if (some_other_state == 0) + some_state <= 2'b00; + default: + $display ("This is a display statement"); + endcase + + if (wrclk) + some_other_state <= 0; + end + +endmodule + +`define BROKEN + +module t1( + input [3:0] i_clks, + input i_clk0, + input i_clk1 + ); + + some_module + some_module + ( +`ifdef BROKEN + .wrclk (i_clks[3]) +`else + .wrclk (i_clk1) +`endif + ); +endmodule + +module t2( + input [2:0] i_clks, + input i_clk0, + input i_clk1, + input i_clk2, + input i_data + ); + logic [3:0] the_clks; + logic data_q; + + assign the_clks = {i_clk1, i_clk2, i_clk1, i_clk0}; + + always @(posedge i_clk0) begin + data_q <= i_data; + end + + t1 t1 + ( + .i_clks (the_clks), + .i_clk0 (i_clk0), + .i_clk1 (i_clk1) + ); +endmodule + +module t( + input clk0 /*verilator clocker*/, + input clk1 /*verilator clocker*/, + input clk2 /*verilator clocker*/, + input data_in + ); + + logic [2:0] clks; + + assign clks = {1'b0, clk1, clk0}; + + t2 + t2 + ( + .i_clks (clks), + .i_clk0 (clk0), + .i_clk1 (clk1), + .i_clk2 (clk2), + .i_data (data_in) + ); + + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_clk_concat2.pl b/test_regress/t/t_clk_concat2.pl new file mode 100755 index 000000000..1118f2e0e --- /dev/null +++ b/test_regress/t/t_clk_concat2.pl @@ -0,0 +1,18 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 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 Version 3 or the Perl Artistic License +# Version 2.0. + +compile ( + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_clk_concat2.v b/test_regress/t/t_clk_concat2.v new file mode 100644 index 000000000..746b55ddb --- /dev/null +++ b/test_regress/t/t_clk_concat2.v @@ -0,0 +1,106 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty. +// + +module some_module ( + input wrclk + ); + + logic [ 1 : 0 ] some_state; + logic [1:0] some_other_state; + + always @(posedge wrclk) begin + case (some_state) + 2'b11: + if (some_other_state == 0) + some_state <= 2'b00; + default: + $display ("This is a display statement"); + endcase + + if (wrclk) + some_other_state <= 0; + end + +endmodule + +`define BROKEN + +module t1( + input [3:0] i_clks, + input i_clk0, + input i_clk1 + ); + + some_module + some_module + ( +`ifdef BROKEN + .wrclk (i_clks[3]) +`else + .wrclk (i_clk1) +`endif + ); +endmodule + +module t2( + input [2:0] i_clks, + input i_clk0, + input i_clk1, + input i_clk2, + input i_data + ); + logic [3:0] the_clks; + logic data_q; + + assign the_clks[3] = i_clk1; + assign the_clks[2] = i_clk2; + assign the_clks[1] = i_clk1; + assign the_clks[0] = i_clk0; + + always @(posedge i_clk0) begin + data_q <= i_data; + end + + t1 t1 + ( + .i_clks (the_clks), + .i_clk0 (i_clk0), + .i_clk1 (i_clk1) + ); +endmodule + +module t( + /*AUTOARG*/ + // Inputs + clk /*verilator clocker*/, + input clk0 /*verilator clocker*/, + input clk1 /*verilator clocker*/, + input clk2 /*verilator clocker*/, + input data_in + ); + + input clk; + + logic [2:0] clks; + + assign clks = {1'b0, clk1, clk0}; + + t2 + t2 + ( + .i_clks (clks), + .i_clk0 (clk0), + .i_clk1 (clk), + .i_clk2 (clk2), + .i_data (data_in) + ); + + always @(posedge clk) begin + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_clk_concat3.pl b/test_regress/t/t_clk_concat3.pl new file mode 100755 index 000000000..1118f2e0e --- /dev/null +++ b/test_regress/t/t_clk_concat3.pl @@ -0,0 +1,18 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 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 Version 3 or the Perl Artistic License +# Version 2.0. + +compile ( + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_clk_concat3.v b/test_regress/t/t_clk_concat3.v new file mode 100644 index 000000000..37c164890 --- /dev/null +++ b/test_regress/t/t_clk_concat3.v @@ -0,0 +1,101 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty. +// + +/* verilator lint_off LITENDIAN */ +module some_module ( + input wrclk + ); + + logic [ 1 : 0 ] some_state; + logic [1:0] some_other_state; + + always @(posedge wrclk) begin + case (some_state) + 2'b11: + if (some_other_state == 0) + some_state <= 2'b00; + default: + $display ("This is a display statement"); + endcase + + if (wrclk) + some_other_state <= 0; + end + +endmodule + +`define BROKEN + +module t1( + input [-12:-9] i_clks, + input i_clk0, + input i_clk1 + ); + + some_module + some_module + ( +`ifdef BROKEN + .wrclk (i_clks[-12]) +`else + .wrclk (i_clk1) +`endif + ); +endmodule + +module t2( + input [2:0] i_clks, + input i_clk0, + input i_clk1, + input i_clk2, + input i_data + ); + logic [-12:-9] the_clks; + logic data_q; + + assign the_clks[-12] = i_clk1; + assign the_clks[-11] = i_clk2; + assign the_clks[-10] = i_clk1; + assign the_clks[-9] = i_clk0; + + always @(posedge i_clk0) begin + data_q <= i_data; + end + + t1 t1 + ( + .i_clks (the_clks), + .i_clk0 (i_clk0), + .i_clk1 (i_clk1) + ); +endmodule + +module t( + input clk0 /*verilator clocker*/, + input clk1 /*verilator clocker*/, + input clk2 /*verilator clocker*/, + input data_in + ); + + logic [2:0] clks; + + assign clks = {1'b0, clk1, clk0}; + + t2 + t2 + ( + .i_clks (clks), + .i_clk0 (clk0), + .i_clk1 (clk1), + .i_clk2 (clk2), + .i_data (data_in) + ); + + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_clk_concat4.pl b/test_regress/t/t_clk_concat4.pl new file mode 100755 index 000000000..1118f2e0e --- /dev/null +++ b/test_regress/t/t_clk_concat4.pl @@ -0,0 +1,18 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 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 Version 3 or the Perl Artistic License +# Version 2.0. + +compile ( + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_clk_concat4.v b/test_regress/t/t_clk_concat4.v new file mode 100644 index 000000000..ace301afd --- /dev/null +++ b/test_regress/t/t_clk_concat4.v @@ -0,0 +1,105 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty. +// + +module some_module ( + input wrclk + ); + + logic [ 1 : 0 ] some_state; + logic [1:0] some_other_state; + + always @(posedge wrclk) begin + case (some_state) + 2'b11: + if (some_other_state == 0) + some_state <= 2'b00; + default: + $display ("This is a display statement"); + endcase + + if (wrclk) + some_other_state <= 0; + end + +endmodule + +`define BROKEN + +module t1( + input [3:0] i_clks, + input i_clk0, + input i_clk1 + ); + + generate + genvar i; + for (i = 0; i < 2; i = i + 1) begin: a_generate_block + some_module + some_module + ( +`ifdef BROKEN + .wrclk (i_clks[3]) +`else + .wrclk (i_clk1) +`endif + ); + end + endgenerate +endmodule + +module t2( + input [2:0] i_clks, + input i_clk0, + input i_clk1, + input i_clk2, + input i_data + ); + logic [3:0] the_clks; + logic data_q; + + assign the_clks[3] = i_clk1; + assign the_clks[2] = i_clk2; + assign the_clks[1] = i_clk1; + assign the_clks[0] = i_clk0; + + always @(posedge i_clk0) begin + data_q <= i_data; + end + + t1 t1 + ( + .i_clks (the_clks), + .i_clk0 (i_clk0), + .i_clk1 (i_clk1) + ); +endmodule + +module t( + input clk0 /*verilator clocker*/, + input clk1 /*verilator clocker*/, + input clk2 /*verilator clocker*/, + input data_in + ); + + logic [2:0] clks; + + assign clks = {1'b0, clk1, clk0}; + + t2 + t2 + ( + .i_clks (clks), + .i_clk0 (clk0), + .i_clk1 (clk1), + .i_clk2 (clk2), + .i_data (data_in) + ); + + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_clk_concat5.pl b/test_regress/t/t_clk_concat5.pl new file mode 100755 index 000000000..1118f2e0e --- /dev/null +++ b/test_regress/t/t_clk_concat5.pl @@ -0,0 +1,18 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 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 Version 3 or the Perl Artistic License +# Version 2.0. + +compile ( + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_clk_concat5.v b/test_regress/t/t_clk_concat5.v new file mode 100644 index 000000000..1c126e3b1 --- /dev/null +++ b/test_regress/t/t_clk_concat5.v @@ -0,0 +1,104 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty. +// + +module some_module ( + input [3:0] i_clks + ); + + logic [ 1 : 0 ] some_state; + logic [1:0] some_other_state; + + always @(posedge i_clks[3]) begin + case (some_state) + 2'b11: + if (some_other_state == 0) + some_state <= 2'b00; + default: + $display ("This is a display statement"); + endcase + + if (i_clks[3]) + some_other_state <= 0; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule + +`define BROKEN + +module t1( + input [3:0] i_clks, + input i_clk0, + input i_clk1 + ); + + some_module + some_module + ( + .i_clks (i_clks) + ); +endmodule + +module t2( + input [2:0] i_clks, + input i_clk0, + input i_clk1, + input i_clk2, + input i_data + ); + logic [3:0] the_clks; + logic data_q; + + assign the_clks[3] = i_clk1; + assign the_clks[2] = i_clk2; + assign the_clks[1] = i_clk1; + assign the_clks[0] = i_clk0; + + always @(posedge i_clk0) begin + data_q <= i_data; + end + + t1 t1 + ( + .i_clks (the_clks), + .i_clk0 (i_clk0), + .i_clk1 (i_clk1) + ); +endmodule + +module t( + /*AUTOARG*/ + // Inputs + clk /*verilator clocker*/, + input clk0 /*verilator clocker*/, + input clk1 /*verilator clocker*/, + input clk2 /*verilator clocker*/, + input data_in + ); + + input clk; + + logic [2:0] clks; + + assign clks = {1'b0, clk1, clk0}; + + t2 + t2 + ( + .i_clks (clks), + .i_clk0 (clk0), + .i_clk1 (clk), + .i_clk2 (clk2), + .i_data (data_in) + ); + + // initial begin + // $write("*-* All Finished *-*\n"); + // $finish; + // end +endmodule diff --git a/test_regress/t/t_clk_concat6.pl b/test_regress/t/t_clk_concat6.pl new file mode 100755 index 000000000..1118f2e0e --- /dev/null +++ b/test_regress/t/t_clk_concat6.pl @@ -0,0 +1,18 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 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 Version 3 or the Perl Artistic License +# Version 2.0. + +compile ( + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_clk_concat6.v b/test_regress/t/t_clk_concat6.v new file mode 100644 index 000000000..106bb3de6 --- /dev/null +++ b/test_regress/t/t_clk_concat6.v @@ -0,0 +1,113 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty. +// + +module some_module ( + input [3:0] i_clks + ); + + logic [ 1 : 0 ] some_state; + logic [1:0] some_other_state; + logic the_clk; + + assign the_clk = i_clks[3]; + + always @(posedge the_clk) begin + case (some_state) + 2'b11: + if (some_other_state == 0) + some_state <= 2'b00; + default: + $display ("This is a display statement"); + endcase + + if (the_clk) + some_other_state <= 0; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule + +`define BROKEN + +module t1( + input [3:0] i_clks, + input i_clk0, + input i_clk1 + ); + + some_module + some_module + ( + .i_clks (i_clks) + ); +endmodule + +module ident( + input i_ident, + output o_ident + ); + assign o_ident = i_ident; +endmodule + +module t2( + input [2:0] i_clks, + input i_clk0, + input i_clk1, + input i_clk2, + input i_data + ); + logic [3:0] the_clks; + logic data_q; + logic ident_clk1; + + always @(posedge i_clk0) begin + data_q <= i_data; + end + + ident + ident + ( + .i_ident (i_clk1), + .o_ident (ident_clk1) + ); + + t1 t1 + ( + .i_clks ({ident_clk1, i_clk2, ident_clk1, i_clk0}), + .i_clk0 (i_clk0), + .i_clk1 (i_clk1) + ); +endmodule + +module t( + /*AUTOARG*/ + // Inputs + clk /*verilator clocker*/ /*verilator public_flat*/, + input clk0 /*verilator clocker*/, + input clk1 /*verilator clocker*/, + input clk2 /*verilator clocker*/, + input data_in + ); + + input clk; + + logic [2:0] clks; + + assign clks = {1'b0, clk1, clk0}; + + t2 + t2 + ( + .i_clks (clks), + .i_clk0 (clk0), + .i_clk1 (clk), + .i_clk2 (clk2), + .i_data (data_in) + ); + +endmodule