Verilog中基于快慢时钟生成重复脉冲的问题排查
It sounds like your issue stems from not properly detecting each slow clock edge in the fast domain, or having a state in your pulse logic that doesn’t reset to allow re-triggering. Cross-clock pulse generation requires careful handling of domain synchronization and edge detection to ensure pulses repeat reliably.
Let’s break down the root causes and a solution that will generate your cnt_write_fifo pulse on every slow clock rising edge, with the pulse lasting exactly one fast clock cycle (disappearing on the next fast rising edge):
Common Reasons Your Pulse Only Triggers Once
- Missing Edge Detection Reset: If your edge detection logic sets a flag but never clears it, it won’t recognize subsequent slow clock edges.
- Poor Cross-Domain Synchronization: Not using synchronizer flops can lead to metastability, or your synchronized signal might not change state between slow clock cycles.
- Incorrect Pulse Generation: If your pulse isn’t cleared after one fast cycle, it might stay high or get stuck in a non-triggerable state.
Working Implementation
Here’s a robust Verilog module that addresses these issues. We’ll use a toggle signal from the slow domain to ensure every slow clock edge creates a detectable transition in the fast domain:
module cross_clock_pulse ( input clk_slow, // Slow clock domain input clk_fast, // Fast clock domain (higher frequency) input rst_n, // Active-low asynchronous reset output reg cnt_write_fifo // Pulse: high for 1 fast cycle on each slow rising edge ); // Step 1: Create a toggle signal in the slow domain (changes every slow clock cycle) reg slow_toggle; always @(posedge clk_slow or negedge rst_n) begin if (!rst_n) begin slow_toggle <= 1'b0; end else begin slow_toggle <= ~slow_toggle; end end // Step 2: Synchronize the slow toggle signal into the fast domain (2 flops for metastability protection) reg [1:0] sync_slow_toggle; always @(posedge clk_fast or negedge rst_n) begin if (!rst_n) begin sync_slow_toggle <= 2'b00; end else begin sync_slow_toggle <= {sync_slow_toggle[0], slow_toggle}; end end // Step 3: Detect the rising edge of the synchronized slow toggle (indicates a slow clock rising edge) wire slow_edge_detected = sync_slow_toggle[1] & ~sync_slow_toggle[0]; // Step 4: Generate the cnt_write_fifo pulse (high for exactly 1 fast clock cycle) always @(posedge clk_fast or negedge rst_n) begin if (!rst_n) begin cnt_write_fifo <= 1'b0; end else begin cnt_write_fifo <= slow_edge_detected; end end endmodule
How This Works
- Slow Domain Toggle:
slow_toggleflips state every slow clock rising edge. This ensures there’s a clear transition to detect in the fast domain, even if the slow clock is much slower than the fast one. - Synchronization: The two-flop synchronizer (
sync_slow_toggle) safely brings the slow-domain signal into the fast domain, eliminating metastability risks. - Edge Detection:
slow_edge_detectedgoes high for exactly one fast clock cycle each time the synchronized toggle rises, which corresponds to a slow clock rising edge. - Pulse Generation:
cnt_write_fifotakes this edge detection signal directly, resulting in a single fast-cycle pulse that repeats every slow clock edge.
Key Checks for Your Original Code
- Did you use a two-flop synchronizer for any slow-domain signals entering the fast domain?
- Does your edge detection logic reset after each pulse (i.e., it doesn’t stay in a "detected" state permanently)?
- Is your pulse signal cleared after one fast clock cycle, allowing it to be re-triggered?
This implementation should resolve your simulation issue and make cnt_write_fifo pulse reliably on every slow clock rising edge.
内容的提问来源于stack exchange,提问作者Joanna14071

