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.