// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2010 by 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

   // 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]));

endmodule
