// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2010 Wilson Snyder
// SPDX-License-Identifier: CC0-1.0
//
//    --------------------------------------------------------
//    Bug Description:
//
//    Issue:  The gated clock gclk_vld[0] toggles but dvld[0]
//    input to the flop does not propagate to the output
//    signal entry_vld[0] correctly. The value that propagates
//    is the new value of dvld[0] not the one just before the
//    posedge of gclk_vld[0].
//    --------------------------------------------------------

// Define to see the bug with test failing with gated clock 'gclk_vld'
// Comment out the define to see the test passing with ungated clock 'clk'
`define GATED_CLK_TESTCASE 1

// A side effect of the problem is this warning, disabled by default

// Test Bench
module t (  /*AUTOARG*/
    // Inputs
    clk
);
  input clk;

  integer cyc = 0;
  reg [63:0] crc;

  // Take CRC data and apply to testblock inputs
  wire [7:0] dvld = crc[7:0];
  wire [7:0] ff_en_e1 = crc[15:8];

  /*AUTOWIRE*/
  // Beginning of automatic wires (for undeclared instantiated-module outputs)
  wire [7:0] entry_vld;  // From test of Test.v
  wire [7:0] ff_en_vld;  // From test of Test.v
  // End of automatics

  Test test (  /*AUTOINST*/
      // Outputs
      .ff_en_vld(ff_en_vld[7:0]),
      .entry_vld(entry_vld[7:0]),
      // Inputs
      .clk(clk),
      .dvld(dvld[7:0]),
      .ff_en_e1(ff_en_e1[7:0])
  );

  reg err_code;
  reg ffq_clk_active;
  reg [7:0] prv_dvld;

  initial begin
    err_code = 0;
    ffq_clk_active = 0;
  end
  always @(posedge clk) begin
    prv_dvld = test.dvld;
  end
  always @(negedge test.ff_entry_dvld_0.clk) begin
    ffq_clk_active = 1;
    if (test.entry_vld[0] !== prv_dvld[0]) err_code = 1;
  end

  // Test loop
  always @(posedge clk) begin
`ifdef TEST_VERBOSE
    $write("[%0t] cyc==%0d crc=%x ", $time, cyc, crc);
    $display(" en=%b fen=%b d=%b ev=%b", test.flop_en_vld[0], test.ff_en_vld[0], test.dvld[0],
             test.entry_vld[0]);
`endif
    cyc <= cyc + 1;
    crc <= {crc[62:0], crc[63] ^ crc[2] ^ crc[0]};
    if (cyc < 3) begin
      crc <= 64'h5aef0c8d_d70a4497;
    end
    else if (cyc == 99) begin
      $write("[%0t] cyc==%0d crc=%x\n", $time, cyc, crc);
      if (ffq_clk_active == 0) begin
        $display("----");
        $display("%%Error: TESTCASE FAILED with no Clock arriving at FFQs");
        $display("----");
        $stop;
      end
      else if (err_code) begin
        $display("----");
        $display("%%Error: TESTCASE FAILED with invalid propagation of 'd' to 'q' of FFQs");
        $display("----");
        $stop;
      end
      else begin
        $write("*-* All Finished *-*\n");
        $finish;
      end
    end
  end

endmodule

module llq (
    clk,
    d,
    q
);
  parameter WIDTH = 32;
  input clk;
  input [WIDTH-1:0] d;
  output [WIDTH-1:0] q;

  reg [WIDTH-1:0] qr;

  /* verilator lint_off COMBDLY */
  /* verilator lint_off LATCH */

  always @(clk or d) if (clk == 1'b0) qr <= d;

  /* verilator lint_on LATCH */
  /* verilator lint_on COMBDLY */

  assign q = qr;
endmodule

module ffq (
    clk,
    d,
    q
);
  parameter WIDTH = 32;
  input clk;
  input [WIDTH-1:0] d;
  output [WIDTH-1:0] q;

  reg [WIDTH-1:0] qr;

  always @(posedge clk) qr <= d;

  assign q = qr;
endmodule

// DUT module
module Test (  /*AUTOARG*/
    // Outputs
    ff_en_vld,
    entry_vld,
    // Inputs
    clk,
    dvld,
    ff_en_e1
);
  input clk;

  input [7:0] dvld;
  input [7:0] ff_en_e1;

  output [7:0] ff_en_vld;
  output wire [7:0] entry_vld;

  wire [7:0] gclk_vld;
  wire [7:0] ff_en_vld;
  reg [7:0] flop_en_vld;

  always @(posedge clk) flop_en_vld <= ff_en_e1;

  // clock gating
`ifdef GATED_CLK_TESTCASE
  assign gclk_vld = {8{clk}} & ff_en_vld;
`else
  assign gclk_vld = {8{clk}};
`endif

  // verilog_format: off
  // latch for avoiding glitch on the clock gating control
  llq  #(8)  dp_ff_en_vld (.clk(clk), .d(flop_en_vld), .q(ff_en_vld));

  // flops that use the gated clock signal
  ffq  #(1)  ff_entry_dvld_0 (.clk(gclk_vld[0]), .d(dvld[0]), .q(entry_vld[0]));
  ffq  #(1)  ff_entry_dvld_1 (.clk(gclk_vld[1]), .d(dvld[1]), .q(entry_vld[1]));
  ffq  #(1)  ff_entry_dvld_2 (.clk(gclk_vld[2]), .d(dvld[2]), .q(entry_vld[2]));
  ffq  #(1)  ff_entry_dvld_3 (.clk(gclk_vld[3]), .d(dvld[3]), .q(entry_vld[3]));
  ffq  #(1)  ff_entry_dvld_4 (.clk(gclk_vld[4]), .d(dvld[4]), .q(entry_vld[4]));
  ffq  #(1)  ff_entry_dvld_5 (.clk(gclk_vld[5]), .d(dvld[5]), .q(entry_vld[5]));
  ffq  #(1)  ff_entry_dvld_6 (.clk(gclk_vld[6]), .d(dvld[6]), .q(entry_vld[6]));
  ffq  #(1)  ff_entry_dvld_7 (.clk(gclk_vld[7]), .d(dvld[7]), .q(entry_vld[7]));
  // verilog_format: on

endmodule
