Pulse ↔ Level Conversions

from FPGA Resources by GateForge Consulting Ltd.

Sometimes, you need to convert a steady logic level into a single pulse, or vice-versa. For example, when you need to capture and hold a transient event until your FSM reaches the state that will react to the event, or when you need some steady condition to be acted upon exactly once, without having to add yet another FSM or counter to do just that. Converting between levels and pulses also happens when interfacing to other logic or external hardware.

We can do pulse/level conversions with a pair of small, useful gadgets: a pulse latch, and a pulse generator.


A pulse latch simply catches a positive pulse into a register and loops its output back to the input, gated by a clear signal to return the output level to zero. All inputs and outputs are synchronous to the clock, and so must last a minimum of one clock cycle. Although shown as plain Boolean logic, the actual implementation will differ depending on your CAD tools and target FPGA (e.g.: using synchronous set/reset pins rather than logic gates).

// Latch pulse to level, until cleared

`default_nettype none

module pulse_latch
(
    input   wire    clock,
    input   wire    clear,
    input   wire    pulse_in,
    output  reg     level_out
);

    initial begin
        level_out = 1'b0;
    end

    reg level_out_next = 1'b0;

    always @(*) begin
        level_out_next  = pulse_in | level_out;
        level_out       = (clear == 1'b1) ? 1'b0 : level_out_next;
    end

    always @(posedge clock) begin
        level_out <= level_out_next;
    end

endmodule

Alternatively, the pulse latch logic could be written in a behavioural style rather than structural. I find behavioural code clearer to read. Note the use of blocking statements in both version to split the logic into simple steps.

    always @(*) begin
        level_out_next  = (pulse_in == 1'b1) ? pulse_in : level_out;
        level_out       = (clear    == 1'b1) ? 1'b0     : level_out_next;
    end

A pulse generator works by comparing a signal with a delayed version of itself. Until the delayed version catches up, the pulse output is asserted. We can adjust the length of the pulse, in clock cycles, by using a parameterizable delay line. How you do the comparison determines when a pulse is generated. In this example, we AND the input signal with a delayed and inverted version, so when the input has a positive edge (low-to-high), the output goes high until the delayed input arrives also. Inverting the input gives you a positive pulse on an input negative edge. Using an XOR gives you a positive pulse on either input edge.

// Posedge Pulse Generator
// Convert a rising edge to a pulse.
// No output on falling edge.

`default_nettype none

module posedge_pulse_generator
#(
    parameter PULSE_LENGTH = 0
)
(
    input   wire    clock,
    input   wire    level_in,
    output  reg     pulse_out
);

    initial begin
        pulse_out = 0;
    end

    wire level_delayed;

    Delay_Line 
    #(
        .DEPTH  (PULSE_LENGTH), 
        .WIDTH  (1)
    )  
    pulse_length_adjuster
    (
        .clock   (clock),
        .in      (level_in),
        .out     (level_delayed)
    );

    always @(*) begin
        pulse_out = level_in & ~level_delayed;
    end

endmodule

The equivalent behavioural expression would be:

    always @(*) begin
        pulse_out = (level_in == 1'b1) && (level_delayed == 1'b0);
    end

I'm curious if it could be shown that a pulse latch is a degenerate FSM, and a pulse generator a degenerate counter.


fpgacpu.ca