A positive edge detector produces a pulse on its output when the signal it monitors changes from 0 to 1. In Verilog, it is built by delaying the signal by one clock cycle with a flip-flop and combining the delayed copy with the current value: pe = sig & ~sig_dly is high only when the signal is 1 now and was 0 one cycle earlier.
10 min read | Beginner Level
What You'll Learn
- How a one-cycle delay and an AND gate detect a rising edge
- Write positive, negative and any-edge detectors in Verilog
- What the design synthesizes into, down to FPGA primitives
- Why asynchronous inputs need a synchronizer and a registered output
Design
The detector keeps a copy of the input that is one clock cycle old, called sig_dly. At any moment, comparing the two tells you what happened at the last clock edge:
| sig_dly (previous) | sig (current) | pe = sig & ~sig_dly | Meaning |
|---|---|---|---|
| 0 | 0 | 0 | Stayed low |
| 0 | 1 | 1 | Rising edge |
| 1 | 0 | 0 | Falling edge |
| 1 | 1 | 0 | Stayed high |
Inverting the delayed copy and ANDing it with the current input gives 1 in exactly one row: the rising edge.
module pos_edge_det ( input sig, // Input signal for which positive edge has to be detected
input clk, // Input signal for clock
output pe); // Output signal that gives a pulse when a positive edge occurs
reg sig_dly; // Internal signal to store the delayed version of signal
// This always block ensures that sig_dly is exactly 1 clock behind sig
always @ (posedge clk) begin
sig_dly <= sig;
end
// Combinational logic where sig is AND with delayed, inverted version of sig
// Assign statement assigns the evaluated expression in the RHS to the internal net pe
assign pe = sig & ~sig_dly;
endmodule

When sig rises, pe goes high immediately. At the next rising clock edge, sig_dly captures the 1, ~sig_dly becomes 0, and pe goes low again. If sig changes right at a clock edge, as it does when it comes from other logic on the same clock, pe is exactly one clock cycle wide.
Negative and Any-Edge Detection
The same flip-flop supports the other edge types by changing only the gate:
assign pe = sig & ~sig_dly; // Rising edge: now 1, was 0
assign ne = ~sig & sig_dly; // Falling edge: now 0, was 1
assign ae = sig ^ sig_dly; // Any edge: now differs from before
Quick Check
Q: sig stays high for 10 clock cycles. How many clock cycles is pe high?
Show Answer
One, at most. pe is high only until the first clock edge after the rise, when sig_dly becomes 1. For the rest of the time sig is high, both inputs of the comparison are 1 and pe stays 0. This is what makes an edge detector useful: a long level becomes a single event.
Where are Edge Detectors Used?
A push button on a development board or appliance stays pressed for many milliseconds, which is millions of clock cycles. After debouncing, an edge detector turns each press into one pulse, so a counter or menu advances once per press instead of continuously while the button is held. See Verilog Debounce Circuit.
Testbench
The testbench uses a clock period of 10 time units, which is 100 MHz if the time unit is 1 ns. It raises sig twice: once in step with a clock edge, and once between edges.
module tb;
reg sig; // Declare internal TB signal called sig to drive the sig pin of the design
reg clk; // Declare internal TB signal called clk to drive clock to the design
wire pe; // Declare a wire to observe the pe output of the design
// Instantiate the design in TB and connect with signals in TB
pos_edge_det ped0 ( .sig(sig),
.clk(clk),
.pe(pe));
// Generate a clock with a period of 10 time units (100 MHz with a 1 ns time unit)
always #5 clk = ~clk; // Rising edges at 5, 15, 25, ...
// Drive stimulus to the design
initial begin
clk <= 0;
sig <= 0;
#15 sig <= 1; // t=15: rises together with a clock edge
#20 sig <= 0; // t=35
#15 sig <= 1; // t=50: rises between clock edges
#10 sig <= 0; // t=60
#20 $finish;
end
endmodule

In the waveform:
- First rise, t=15:
sigchanges on the clock edge, so the flip-flop still captures the old 0 at that edge.peis high from 15 to 25, one full clock cycle. - Second rise, t=50:
sigchanges halfway between the edges at 45 and 55.pegoes high at 50 and low at 55, whensig_dlycatches up, so the pulse is only half a clock cycle wide. - Before the first clock edge:
sig_dlyhas no value yet (x), butsigis 0, sope = 0 & ~xis already 0.pewould only be x ifsigwere 1.
The short second pulse shows a property of this design: because pe comes directly from sig through a gate, its width depends on when sig changes. That is fine when sig is produced by logic on the same clock, but not when it is an external or asynchronous signal, as explained below.
Quick Check
Q: Suppose the second rise of sig happened at t=54 instead of t=50. How wide would the pulse on pe be, and why is that a problem for logic clocked by clk?
Show Answer
1 time unit, from 54 to 55, because sig_dly catches up at the clock edge at 55. A flip-flop that samples pe at 55 needs it to be stable for its setup time before the edge. A pulse that starts just before the edge may violate that requirement, so the event can be missed or the flip-flop can go metastable. The registered design shown below avoids this.
Hardware Schematic
The design was synthesized with an FPGA synthesis tool. The one-cycle delay becomes a D flip-flop, and its output passes through an inverter into an AND gate together with sig. In the schematic, the generic gates have been mapped to cells of the target technology.

Synthesized Netlist
The netlist below targets an Artix-7 FPGA and lists the primitives the design uses:
IBUFandOBUF- Input and output buffers for the pinsBUFG- Global clock buffer that distributesclkFDRE- D flip-flop with clock enable and synchronous reset, used assig_dly; its enable is tied high and its reset lowLUT2- A 2-input lookup table implementingsig & ~sig_dlyGNDandVCC- Constant 0 and 1 sources for the tied-off pins
module pos_edge_det
(sig,
clk,
pe);
input sig;
input clk;
output pe;
wire \<const0> ;
wire \<const1> ;
wire clk;
wire clk_IBUF;
wire clk_IBUF_BUFG;
wire pe;
wire pe_OBUF;
wire sig;
wire sig_IBUF;
wire sig_dly;
GND GND
(.G(\<const0> ));
VCC VCC
(.P(\<const1> ));
BUFG clk_IBUF_BUFG_inst
(.I(clk_IBUF),
.O(clk_IBUF_BUFG));
IBUF clk_IBUF_inst
(.I(clk),
.O(clk_IBUF));
OBUF pe_OBUF_inst
(.I(pe_OBUF),
.O(pe));
LUT2 #(
.INIT(4'h2))
pe_OBUF_inst_i_1
(.I0(sig_IBUF),
.I1(sig_dly),
.O(pe_OBUF));
IBUF sig_IBUF_inst
(.I(sig),
.O(sig_IBUF));
FDRE #(
.INIT(1'b0))
sig_dly_reg
(.C(clk_IBUF_BUFG),
.CE(\<const1> ),
.D(sig_IBUF),
.Q(sig_dly),
.R(\<const0> ));
endmodule
The INIT value of a LUT is its truth table. For a LUT2, bit n of INIT is the output when {I1, I0} equals n. 4'h2 is 4'b0010, so the output is 1 only for {I1, I0} = 2'b01, which is sig_dly = 0 and sig = 1: exactly the rising-edge row of the table above. The FDRE's INIT(1'b0) means that on an FPGA, sig_dly starts at 0 after configuration, unlike the x seen in simulation.
Edge-Triggered Interrupts
Interrupt controllers in microcontrollers let each interrupt line be configured as level-triggered or edge-triggered. In edge mode, an edge detector on the synchronized input sets a pending bit for one event per rising or falling edge, even if the external signal then stays high or low for a long time.
Registered Output and Asynchronous Inputs
When sig comes from outside the clock domain, such as a pin, a button or a block on a different clock, two changes make the detector reliable:
- Synchronize the input through two flip-flops before using it. An asynchronous signal can change just as a flip-flop samples it, which can leave the flip-flop metastable for a short time. The second flip-flop gives that state time to settle.
- Register the output by computing it from two flip-flop outputs instead of the raw input. The pulse is then exactly one clock cycle wide, and it starts and ends on clock edges.
module pos_edge_det_sync (
input clk,
input rstn, // Active-low synchronous reset
input sig, // Asynchronous input
output pe // One-cycle pulse, aligned to clk
);
reg sig_s1, sig_s2, sig_dly;
always @(posedge clk) begin
if (!rstn) begin
sig_s1 <= 1'b0;
sig_s2 <= 1'b0;
sig_dly <= 1'b0;
end else begin
sig_s1 <= sig; // Synchronizer stage 1 (may go metastable)
sig_s2 <= sig_s1; // Synchronizer stage 2 (settled value)
sig_dly <= sig_s2; // One cycle older copy for edge detection
end
end
// Both inputs come from flip-flops, so pe changes only on clock edges
assign pe = sig_s2 & ~sig_dly;
endmodule
The pulse now appears two to three clock cycles after the input changes, but it always lasts exactly one cycle and can never be shortened by the input's timing. The reset also removes the x at the start of simulation.
Start Pulses for State Machines
A control register bit written by software often stays set until software clears it, while the hardware block it controls needs a single "start" pulse. An edge detector on that bit produces the pulse, so the block starts once per write and does not restart on every cycle that the bit remains set.
Common Beginner Mistakes
Mistake #1: Using the signal as a clock
Wrong: always @(posedge sig) pe_count <= pe_count + 1;
Right: Detect the edge with sig & ~sig_dly and use it as an enable in logic clocked by clk
Why? posedge sig makes sig a clock, creating a new clock domain that timing analysis must handle separately. A noisy or glitching signal also produces extra clock edges. An edge detector keeps all logic on the system clock.
Mistake #2: Inverting the wrong signal
Wrong: assign pe = ~sig & sig_dly; for a rising edge
Right: assign pe = sig & ~sig_dly;
Why? ~sig & sig_dly means "now 0, was 1", which is a falling edge. Check the expression against the truth table: the rising edge is the row where the current value is 1 and the delayed value is 0.
Mistake #3: Feeding an asynchronous input straight into the detector
Wrong: Connecting a button or another clock domain's signal directly to sig
Right: Pass it through a two-flip-flop synchronizer first, as in pos_edge_det_sync
Why? The pulse width depends on when the input changes, as the second pulse in the testbench shows, and can be too short to be sampled. The first flip-flop can also go metastable. Both problems cause missed or extra events that appear only occasionally in hardware.
Mistake #4: Leaving the delay flip-flop without a reset
Wrong: Relying on sig_dly to start at 0 in simulation
Right: Reset sig_dly to a known value, usually the input's idle level
Why? Until the first clock edge, sig_dly is x, so pe is x too, which can propagate into the logic that uses it. On an ASIC, the flip-flop powers up in an unknown state and can create a false edge. If the input idles high, resetting sig_dly to 1 prevents a false rising edge right after reset.
Practice Exercise
Challenge: Three-Way Edge Detector
Write a module edge_det with inputs clk, rstn and an asynchronous input sig, and three outputs: pe (rising edge), ne (falling edge) and ae (any edge). All three must be one clock cycle wide and come directly from flip-flops, so that they are glitch-free.
Hint
Start from pos_edge_det_sync. To make the outputs come from flip-flops, compute the edge conditions combinationally and register them on the next clock edge.
Solution
module edge_det (
input clk,
input rstn,
input sig, // Asynchronous input
output reg pe, // Rising edge pulse
output reg ne, // Falling edge pulse
output reg ae // Any edge pulse
);
reg s1, s2, s_dly;
always @(posedge clk) begin
if (!rstn) begin
{s1, s2, s_dly} <= 3'b000;
{pe, ne, ae} <= 3'b000;
end else begin
s1 <= sig; // Two-flop synchronizer
s2 <= s1;
s_dly <= s2; // Previous synchronized value
pe <= s2 & ~s_dly; // Registered edge outputs
ne <= ~s2 & s_dly;
ae <= s2 ^ s_dly;
end
end
endmodule
Synthesis builds 6 flip-flops and three small gates, or three LUTs on an FPGA. The outputs appear one cycle later than in pos_edge_det_sync, but since they come straight from flip-flops they cannot glitch, which matters when they drive logic in another block or leave the chip.
Summary
In this tutorial, you learned:
- A positive edge detector compares a signal with a copy delayed by one clock cycle
sig & ~sig_dlydetects a rising edge,~sig & sig_dlya falling edge andsig ^ sig_dlyany edge- The design synthesizes into one flip-flop and one gate, a single LUT2 on an FPGA
- With an unregistered output, the pulse width depends on when the input changes
- Asynchronous inputs need a two-flip-flop synchronizer before edge detection
- Edge detectors turn long level signals into one-cycle events for counters, FSMs and interrupts