How to design Gray code synchronous counters of large widths using SystemVerilog?
The design is partitioned into 2 parts - one for combinational logic and another for sequential logic.

In the sequential logic part, an always_ff block is used. Counter is an internal signal used to store the values and it gets incremented on the positive edge of the clock. Counter is a binary counter, and it has a modulus of 2 raised to the power of its width.

In the combinational logic part, an always_comb block is used, where the binary code to gray code conversion is done. This is done by observing two facts:

The Most Significant Bit is the same as the Most Significant Bit of the binary counter. This assignment can be done using an assign statement.

For other bits, they are the result of the Ex-Or operation on the
corresponding bit of the binary counter and the bit to the immediate right of it. Hence a foreach loop is suitable to iterate over all the bits and perform the Ex-Or operation over the respective bits of the binary counter.




Design:
module gray_ctr
  #(parameter WIDTH=4)
  (input logic clk,                
    input logic reset,
    output logic [WIDTH-1:0] q);    
   
  logic [WIDTH-1:0] counter;
  
  always_ff @ (posedge clk) begin
    if (reset) begin
      counter &lt;= 0;
    end  
    else begin
      counter &lt;= counter + 1;    
    end  
  end
   
  always_comb begin
  q[WIDTH-1] = counter[WIDTH-1];
  foreach (counter[i]) 
    q[i-1] = counter[i]^counter[i-1]; 
  end  
  
endmodule

Testbench:
module tb;
  parameter WIDTH = 4;
  
  reg clk;
  reg rstn;
  wire [WIDTH-1:0] out;
  
  gray_ctr #(WIDTH) u0 (.clk (clk),
                .reset (rstn),
                .q (out));
  
  always #10 clk = ~clk;
  
  initial begin
    {clk, rstn} = 0;
    $dumpfile(&quot;dump.vcd&quot;);
    $dumpvars(1,tb);                
    $monitor (&quot;T=%0t out=%b&quot;, $time, out);
    #50 rstn = 1;
    #50 rstn = 0;
    #50 rstn = 1;
    #50 rstn = 0;
    #800 
    $finish;
  end
  
endmodule