Search code examples
veriloghdlvivadosynthesis

How do you write a parameterized delay register?


I'm attempting to write a general-purpose Verilog latch module with width and delay parameters (delay for synchronization/CDC purposes). At first I wanted to generate a number of delay registers based on the delay parameter, but I decided instead to simply have one shift register, sized according to the delay, as I believe it's cleaner. The code is as follows:

module latch # (
    parameter WIDTH = 32,
    parameter DELAY = 0
  )
  (
    input                  clk,
    input                  resetn,
    input [WIDTH-1:0]      din,
    output reg [WIDTH-1:0] dout
  );

  reg [(WIDTH*(DELAY))-1:0] dly;

  always @ (posedge clk)
  begin
    if (!resetn)
    begin
      dly  <= 0;
      dout <= 0;
    end
    else
    begin
      if (DELAY == 0)
      begin
        dout <= din;
      end
      else
      begin
        dly  <= {dly[(WIDTH*(DELAY-1))-1:0], din};
        dout <= dly[(WIDTH*(DELAY))-1 -: WIDTH];
      end
    end
  end

endmodule

xvlog has no problem with this, even when instantiated with DELAY = 0. However, Vivado synthesis returns:

ERROR: [Synth 8-524] part-select [-1:0] out of range of prefix 'dly'

when this module is instantiated with DELAY = 0. How would you get around this? I thought I might be able to get away with defining a max macro and setting the top index of the register to max(0, (WIDTH*(DELAY-1))-1), but of course that gets rejected as a variable width register. Is it possible to conditionally declare registers based on parameters?


Solution

  • You can try a generate if statement to conditionally declare the registers:

    module latch # (
        parameter WIDTH = 32,
        parameter DELAY = 0
      )
      (
        input                  clk,
        input                  resetn,
        input [WIDTH-1:0]      din,
        output reg [WIDTH-1:0] dout
      );
    
      if (DELAY == 0)
      begin
    
        always @ (posedge clk)
        begin
          if (!resetn)
          begin
            dout <= 0;
          end
          else
          begin
            dout <= din;
          end
        end
    
      end
      else if (DELAY == 1)
      begin
    
        reg [WIDTH-1:0] dly;
    
        always @ (posedge clk)
        begin
          if (!resetn)
          begin
            dly  <= 0;
            dout <= 0;
          end
          else
          begin
            dly  <= din;
            dout <= dly;
          end
        end
    
      end
      else
      begin
    
        reg [(WIDTH*(DELAY))-1:0] dly;
    
        always @ (posedge clk)
        begin
          if (!resetn)
          begin
            dly  <= 0;
            dout <= 0;
          end
          else
          begin
            dly  <= {dly[(WIDTH*(DELAY-1))-1:0], din};
            dout <= dly[(WIDTH*DELAY)-1 -: WIDTH];
          end
        end
      end
    
    endmodule
    

    The generate keyword is optional. Refer to IEEE Std 1800-2017, section 27. Generate constructs