verilator/test_regress/t/t_case_incrdecr.v

163 lines
3.9 KiB
Systemverilog

// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2022 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
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