diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index f68cc16f0..90de66590 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -18,6 +18,7 @@ David Horton David Metz David Stanford David Turner +Drew Ranck Drew Taussig Driss Hafdi Edgar E. Iglesias diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index 9e167e129..f21764919 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -134,6 +134,16 @@ private: iterateAndNextNull(nodep->elsesp()); m_insStmtp = nullptr; } + virtual void visit(AstCaseItem* nodep) override { + m_insMode = IM_BEFORE; + { + VL_RESTORER(m_unsupportedHere); + m_unsupportedHere = true; + iterateAndNextNull(nodep->condsp()); + } + m_insStmtp = nullptr; // Next thing should be new statement + iterateAndNextNull(nodep->bodysp()); + } virtual void visit(AstNodeFor* nodep) override { // LCOV_EXCL_LINE nodep->v3fatalSrc( "For statements should have been converted to while statements in V3Begin.cpp"); diff --git a/test_regress/t/t_case_incrdecr.pl b/test_regress/t/t_case_incrdecr.pl new file mode 100755 index 000000000..abbcf936a --- /dev/null +++ b/test_regress/t/t_case_incrdecr.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env 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 +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + verilator_flags2 => ["--trace --Os -x-assign 0"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_case_incrdecr.v b/test_regress/t/t_case_incrdecr.v new file mode 100644 index 000000000..4b3e6e2fc --- /dev/null +++ b/test_regress/t/t_case_incrdecr.v @@ -0,0 +1,156 @@ +module t + (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + int cyc = 0; + + logic [1:0] case_sel; + + always @ (posedge clk) begin : main + cyc <= cyc + 1; + + case_sel <= 2'($urandom); + + if (cyc > 100) begin + $write("*-* All Finished *-*\n"); + $finish(); + end + end + + + // ------------------------- + // Simple case-stmt with ++/-- + + logic [3:0] count_d; + logic [3:0] count_q = '0; + + logic [3:0] want_count_d; + logic [3:0] want_count_q = '0; + + always_ff @(posedge clk) begin : flops + count_q <= count_d; + want_count_q <= want_count_d; + end + + always @(posedge clk) begin : simple_check + if (cyc > 0) begin + if (count_q !== want_count_q) begin + $error("%m: Checks cyc=%0d, count_q (%0d) !== want_count_q (%0d)", + cyc, count_q, want_count_q); + $stop; // don't finish to fail the test. + end + end + end + + always_comb begin : update_golden_counts + want_count_d = want_count_q; + if (case_sel == 2'b10) + want_count_d++; + else if (case_sel == 2'b01) + want_count_d--; + end + + // Make sure the ++ and -- operators are handled correctly in case stmts. + // Test for https://github.com/verilator/verilator/issues/3346 + always_comb begin : update_counts + count_d = count_q; + case (case_sel) + 2'b10: count_d++; + 2'b01: count_d--; + default : ; + endcase // case (case_sel) + end + + // ------------------------- + // FSM with ++/-- + // A more elaborate case statement, with if-else, for loops, etc + // to confirm that ++/-- is handled by V3LinkInc.cpp + logic [3:0] state_d, state_q; + initial state_q = '0; + logic [3:0] state_counter_d, state_counter_q; + always_ff @(posedge clk) begin + state_q <= state_d; + state_counter_q <= state_counter_d; + end + + + always_comb begin : update_state + state_d = state_q; + state_counter_d = state_counter_q; + case (state_q) + + // state 0, no begin/end, goes to state 1 + 4'd0: state_d = 4'd1; + + // state 1, clears state_counter_d, goes to state 2 + 4'd1: begin + state_d = 4'd2; + state_counter_d = '0; + end + + // state 2, wait until state_counter_d increments to 4. + 4'd2: begin + state_counter_d++; + if (state_counter_q == 4) begin + state_d = 4'd3; + end + end + // state 3, decrements state_counter_d from 5 to 0. + 4'd3: begin + state_counter_d--; + if (state_counter_q == 1) begin + state_d = 4'd4; + end + end + + 4'd4: begin + // add 4 with for-loop and ++. + for (int unsigned i = 0; i < 4; i++) begin + state_counter_d++; + end + + if (state_counter_q == 12) begin + state_counter_d = '0; + state_d = 4'd5; + end + end + + 4'd5: begin + // add 8 with a while loop and go to state 6. + while (state_counter_d <= 7) begin + state_counter_d++; + end + + if (state_counter_d == 8) begin + state_d = 4'd15; + end + end + 4'd15 : begin + // success, stay here. + state_counter_d = 4'd7; // pick and hold some success number. + end + default: ; + endcase // case (state_q) + + end // block: state + + always @(posedge clk) begin : simple_state_check + //$display("%m: debug, cyc=%0d, state_q=%0d, state_counter_q=%0d", + // cyc, state_q, state_counter_q); + if (cyc >= 90) begin + // the above FSM should finish before 90 cycles. + // Make sure we made it to state 4'd15. + if (state_q !== 4'd15 || + state_counter_q !== 4'd7) begin + $error("%m: EOT checks, cyc=%0d, state_q=%0d (want 15), state_counter_q=%0d (want 7)", + cyc, state_q, state_counter_q); + $stop; // don't finish to fail the test. + end + end + end + +endmodule : t diff --git a/test_regress/t/t_incr_void.pl b/test_regress/t/t_incr_void.pl new file mode 100755 index 000000000..5b95e5b74 --- /dev/null +++ b/test_regress/t/t_incr_void.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env 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 +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + verilator_flags2 => ["--Os -x-assign 0"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_incr_void.v b/test_regress/t/t_incr_void.v new file mode 100644 index 000000000..eebf410aa --- /dev/null +++ b/test_regress/t/t_incr_void.v @@ -0,0 +1,55 @@ +module t + (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + int cyc = 0; + + always @ (posedge clk) begin : main + cyc <= cyc + 1; + + if (cyc > 100) begin + $write("*-* All Finished *-*\n"); + $finish(); + end + end + + + + logic [3:0] count_d; + logic [3:0] count_q = '0; + + logic [3:0] want_count_d; + logic [3:0] want_count_q = '0; + + always_ff @(posedge clk) begin : flops + count_q <= count_d; + want_count_q <= want_count_d; + end + + always @(posedge clk) begin : simple_check + if (cyc > 0) begin + if (count_q !== want_count_q) begin + $error("%m: cyc=%0d, count_q (%0d) !== want_count_q (%0d)", + cyc, count_q, want_count_q); + $stop; // don't finish to fail the test. + end + end + end + + always_comb begin : update_golden_counts + want_count_d = want_count_q; + want_count_d += 1'b1; + end + + // make sure an implicit void cast on n++ works as expected. + always_comb begin : update_counts + count_d = count_q; + count_d++; + end + + +endmodule