Verilog: [5] Pulse Stretcher (pulse_stretch.sv)

Broken thoughts:

I study today, but I don’t have time to think about it (bushi)

I have gained a few fans in the past two days, thank you for your attention! I must seriously update, let's make progress together!

Table of contents

1 module function

2 module code

3 Module Ideas

4 TestBench and simulation results


1 module function

Set the parameter WIDTH, so that the received single-cycle pulse can be extended into a pulse signal with a pulse width of WIDTH.

2 module code

//--------------------------------------------------------------------------------
// pulse_stretch.sv
// Konstantin Pavlov, [email protected]
//--------------------------------------------------------------------------------

// INFO --------------------------------------------------------------------------------
// Pulse stretcher/extender module
//   this implementftion uses a simple delay line or counter to stretch pulses
//   WIDTH parameter sets output pulse width
//   if you need variable output poulse width, see pulse_gen.sv module


/* --- INSTANTIATION TEMPLATE BEGIN ---

pulse_stretch #(
  .WIDTH( 8 ),
  .USE_CNTR( 0 )
) ps1 (
  .clk( clk ),
  .nrst( nrst ),
  .in(  ),
  .out(  )
);

--- INSTANTIATION TEMPLATE END ---*/

module pulse_stretch #( parameter
  WIDTH = 8,
  USE_CNTR = 0      // ==0  - stretcher is implemented on delay line
                    // ==1  - stretcher is implemented on counter
)(
  input clk,
  input nrst,

  input in,
  output out
);


localparam CNTR_WIDTH = $clog2(WIDTH) + 1;

generate

  if ( WIDTH == 0 ) begin
    assign out = 0;

  end else if( WIDTH == 1 ) begin
    assign out = in;

  end else begin
    if( USE_CNTR == '0 ) begin
      // delay line

      logic [WIDTH-1:0] shifter = '0;
      always_ff @(posedge clk) begin
        if( ~nrst ) begin
          shifter[WIDTH-1:0] <= '0;
        end else begin
          // shifting
          shifter[WIDTH-1:0] <= {shifter[WIDTH-2:0],in};
        end // nrst
      end // always

      assign out = (shifter[WIDTH-1:0] != '0);

    end else begin
      // counter

      logic [CNTR_WIDTH-1:0] cntr = '0;
      always_ff @(posedge clk) begin
        if( ~nrst ) begin
          cntr[CNTR_WIDTH-1:0] <= '0;
        end else begin
          if( in ) begin
            // setting counter
            cntr[CNTR_WIDTH-1:0] <= CNTR_WIDTH'(WIDTH);
          end else if( out ) begin
            // decrementing counter
            cntr[CNTR_WIDTH-1:0] <= cntr[CNTR_WIDTH-1:0] - 1'b1;
          end
        end // nrst
      end // always

      assign out = (cntr[CNTR_WIDTH-1:0] != '0);

    end
  end // if WIDTH
endgenerate


endmodule

3 Module Ideas

According to the code introduction, a simple delay or counter is used to realize the pulse stretching processing. Let's analyze the implementation process and the points worthy of attention.

1. USE_CNTR (line 29)

The note here mentions that you can choose whether to implement the function of this module through the delay line or the counter, which is directly easy to think of using the generate (line 42) in System Verilog to realize it. We used this structure in the edge detector earlier. Introduced: Portal .

2. $clog2 function (line 40)

Reference blog: http://t.csdn.cn/JzRse

The calculation of $clog2 is log2, which is to find the logarithm of 2, for example, log2(8)=3. Here, by using this function, the bit size CNTR_WIDTH of the counter required for WIDTH is calculated and saved as a constant.

3. The core part of the function (lines 42-88)

Use the generate structure to achieve control over the code implementation. Since there are two implementation methods, I will introduce them separately in two parts.

        3.1 Implementation of delay line (lines 54-64)

The realization of this place I personally think is very ingenious. First, according to the set WIDTH value, create a shift register shifter with a length of WIDTH. Use always_ff to build a D flip-flop. In the case of non-reset, shift it to the left in turn, and put the input signal in to the lowest position, and then check whether the shifter is all 0 to control the value of the current output signal out. If all shifter bits are not all 0, the output is 1.

This method directly controls the output within the required width, but one problem is that if the input pulse is not a cycle, it may cause the output pulse width to be wider than WIDTH after stretching.

        3.2 Counter implementation (lines 69-84)

First of all, for the counter, you need to use the result obtained by calling the log2 function above to construct a counter that just meets the requirements. After that, always_ff is also used to build a D flip-flop. In the case of non-reset, when the input signal in is detected to be high, the value of WIDTH will be stored in cntr. When the output is high level, the counter is subtracted by one cycle by cycle.

The control logic of the output signal out is to detect the value of the counter result cntr, if it is not 0, output 1, otherwise output 0. However, there will also be the same problems encountered in the implementation of the delay line above. Maybe the author himself designed it in this way.

4 TestBench and simulation results

//------------------------------------------------------------------------------
// pulse_stretch_tb.sv
// Konstantin Pavlov, [email protected]
//------------------------------------------------------------------------------

// INFO ------------------------------------------------------------------------
// testbench for pulse_stretch.sv module


`timescale 1ns / 1ps

module pulse_stretch_tb();

logic clk200;
initial begin
  #0 clk200 = 1'b0;
  forever
    #2.5 clk200 = ~clk200;
end

logic rst;
initial begin
  #0 rst = 1'b0;
  #10.2 rst = 1'b1;
  #5 rst = 1'b0;
  //#10000;
  forever begin
    #9985 rst = ~rst;
    #5 rst = ~rst;
  end
end

logic nrst;
assign nrst = ~rst;

logic rst_once;
initial begin
  #0 rst_once = 1'b0;
  #10.2 rst_once = 1'b1;
  #5 rst_once = 1'b0;
end

logic start;
initial begin
  #0 start = 1'b0;
  #100 start = 1'b1;
  #5 start = 1'b0;
end

// Modules under test ==========================================================

pulse_stretch #(
  .WIDTH( 8 ),
  .USE_CNTR( 0 )
) ps1 (
  .clk( clk200 ),
  .nrst( nrst ),
  .in( start ),
  .out(  )
);

pulse_stretch #(
  .WIDTH( 8 ),
  .USE_CNTR( 1 )
) ps2 (
  .clk( clk200 ),
  .nrst( nrst ),
  .in( start ),
  .out(  )
);

endmodule

Let's start to introduce the content of TestBench. Here it is relatively simple and does not involve the multiplexing of previous signals. It simply simulates an input pulse by constructing a clock signal and start, so as to realize the test of the module.

It can be seen that two signals to be tested are instantiated at the end, and the parameters are modified respectively. The former is realized through the delay line, and the latter is realized through the counter.

It can be seen from the simulation waveform that the red waveform is realized by using a delay line, and WIDTH=8 is set. When the input is a pulse of one cycle, a pulse signal with a width of 8 clock cycles will be output. The green waveform is realized by using a counter. When the input pulse arrives, the counter will decrement from 8 to 1 in order to output a pulse signal with an output width of 8 clock cycles. It is consistent with our analysis of the code.


This is the whole content of this issue. If you like my article, don't forget to like + bookmark + follow, and share it with your friends~

Guess you like

Origin blog.csdn.net/Alex497259/article/details/126286909