Design Question - Pulse Generator

You are asked to design a module that generates a pulse, once every 32 clocks. How many ways can you implement the design? Would you do anything different if you are targeting a Xilinx UltraScale+ FPGA?

Design Idea 1 - A 5 bit counter

One of the most common approaches is using a 5-bit counter that runs from 0 to 31. A pulse is generated when the counter rolls over. It’s pretty straightforward.

module pulse_generator
(
   input    logic clk,           // clock
   input    logic rst,           // reset
   output   logic pulse_out      // output pulse
);

   //------------------------------------------------------------
   // local signal declaration
   //------------------------------------------------------------
   logic [4:0] sig_cnt;
   logic       sig_pulse_out;

   //------------------------------------------------------------
   // start of RTL code
   //------------------------------------------------------------
   // Counter to count to 31
   always_ff @(posedge clk)
   begin
      if (rst)
      begin
         sig_cnt <= '0;
      end
      else
      begin
         sig_cnt <= sig_cnt + 1'b1;
      end
   end

   // Pulse Generation
   // The generated pulse is combinatorial
   assign sig_pulse_out = (sig_cnt == 5'd31) ? 1'b1 : 1'b0;

   // Sequential output
   always_ff @(posedge clk)
   begin
      pulse_out <= sig_pulse_out;
   end

endmodule

Design Idea - Using a Counter

Key Points to Consider:

  • Eliminating the rst Signal: In FPGA designs, the rst signal can theoretically be eliminated in a majority of cases. Xilinx FPGAs have a Global Set Reset (GSR) line that initializes all registers to a known state, typically zeros. Even if the synthesis tool randomly distributes the 5 bits between a 0 and a 1, the module will still generate pulses 32 clock cycles apart once it rolls over from all ones to all zeros.
  • Combinatorial sig_pulse_out: Using sig_pulse_out as the block output isn’t optimal. Typically, the output pulse drives other logic or serves as an input to a state machine. This can introduce long combinatorial paths with multiple levels of logic into the design.
  • Using 5'd31 Instead of 5'd0: The pulse generator uses 5'd31 to generate a pulse to avoid creating a stretched pulse when sig_cnt is held at 0 with an asserted rst signal spanning multiple clock cycles.

Design Idea 2 - Shift Register

If you could load a 32 bit shift register with a single bit set to a 1 and all other bits set to zeros, and connect the output of the last stage to the input of the first stage, you would get a Ring Counter which would generate a pulse once every 32 clocks.

Let’s dive into the pros and cons of this approach compared to the previous design:

  • Resource Usage: The shift register implementation requires 32 flip-flops, compared to just 5 flip-flops for the counter-based method. While this might be a drawback in ASIC designs, it fits well with the register-rich fabric of an FPGA.
  • Eliminating Combinatorial Logic: The shift register approach removes the need for an adder and a comparator, which can be part of the critical path in the counter-based method.
  • Routing Delay: With no combinatorial logic between stages, the main component of the critical path is the routing delay between flip-flops. This allows the placer more flexibility in positioning these registers, potentially improving performance.

Now, let’s talk about FPGA-specific optimizations. Xilinx UltraScale+ devices offer SRL16s and SRL32s (LUT Shift Registers) that can be used to implement the ring counter logic. An SRL32 can create a 32-bit shift register using a single LUT and a slice flip-flop for sequential output. By initializing the SRL to 32'h80000000, you insert a single 1 into the shift register.

The SRL-based method is particularly advantageous for larger shift registers. Xilinx tools allow cascading SRLs to form longer chains, making this approach more efficient for a 256-bit ring counter compared to an 8-bit counter.

module pulse_generator_sr
(
   input    logic clk,           // clock
   input    logic rst,           // reset
   output   logic pulse_out      // output pulse
);

   //------------------------------------------------------------
   // local signal declaration
   //------------------------------------------------------------
   (* shreg_extract = "yes" *) logic [4:0] sig_shift_reg = 32'h80000000;
                               logic       sig_pulse_out;

   //------------------------------------------------------------
   // start of RTL code
   //------------------------------------------------------------
   // Counter to count to 31
   always_ff @(posedge clk)
   begin
      sig_shift_reg[30: 0] <= sig_shift_reg[31: 1];
      sig_shift_reg[   31] <= sig_shift_reg[    0];
   end

   // Pulse Generation
   // Any bit of the Shift Register can be used as the output pulse
   assign pulse_out = sig_shift_reg[0];

endmodule

Design Idea - Using a Shift Register

Synthesis Directives

Synthesis directives guide the synthesis tool, nudging it in the right direction to achieve the desired implementation. To ensure SRL (Shift Register LUT) inference, you need to provide the appropriate synthesis directives in your RTL code.

In the example above, shreg_extract is a directive that instructs the synthesis tool to implement the shift register using a LUT.

Key Points to Consider

  • Consistency with Design Idea 1: The rst signal is included in the interface to maintain consistency with Design Idea 1.
  • SRL Primitives and Reset: Notice that rst is not used in the always_ff construct. SRL primitives do not accept a reset input. Including a reset signal would prevent the tool from using the SRL, even if a synthesis directive is specified.
  • Initialization of the shift register is done by specifying the initial value when the signal is declared. (Yes, this is synthesizable!!)

Other Design Ideas

There are other, more unconventional ideas that might be theoretically possible but not practically viable. One such idea is to use a state machine with 32 states, where one of the states produces the required output pulse.

Subscribe to fpgadesign.io

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe