Fix all 10 CDC bugs from report_cdc audit, add overflow guard in range_bin_decimator
CDC fixes across 6 RTL files based on post-implementation report_cdc analysis:
- P0: sync stm32_mixers_enable and new_chirp_pulse to clk_120m via toggle CDC
in radar_transmitter, add ft601 reset synchronizer and USB holding
registers with proper edge detection in usb_data_interface
- P1: add ASYNC_REG to edge_detector, convert new_chirp_frame to toggle CDC,
fix USB valid edge detect to use fully-synced signal
- P2: register Gray encoding in cdc_adc_to_processing source domain, sync
ft601_txe and stm32_mixers_enable for status_reg in radar_system_top
- Safety: add in_bin_count overflow guard in range_bin_decimator to prevent
downstream BRAM corruption
All 13 regression test suites pass (159 individual tests).
This commit is contained in:
@@ -44,6 +44,7 @@ module cdc_adc_to_processing #(
|
||||
|
||||
// Source domain registers
|
||||
reg [WIDTH-1:0] src_data_reg;
|
||||
reg [WIDTH-1:0] src_data_gray; // Gray-encoded in source domain
|
||||
reg [1:0] src_toggle = 2'b00;
|
||||
|
||||
// Destination domain synchronizer registers
|
||||
@@ -54,14 +55,18 @@ module cdc_adc_to_processing #(
|
||||
reg dst_valid_reg = 0;
|
||||
reg [1:0] prev_dst_toggle = 2'b00;
|
||||
|
||||
// Source domain: capture data and toggle — synchronous reset
|
||||
// Source domain: capture data, Gray-encode, and toggle — synchronous reset
|
||||
// Gray encoding is registered in src_clk to avoid combinational logic
|
||||
// before the first synchronizer FF (fixes CDC-10 violations).
|
||||
always @(posedge src_clk) begin
|
||||
if (!reset_n) begin
|
||||
src_data_reg <= 0;
|
||||
src_toggle <= 2'b00;
|
||||
src_data_reg <= 0;
|
||||
src_data_gray <= 0;
|
||||
src_toggle <= 2'b00;
|
||||
end else if (src_valid) begin
|
||||
src_data_reg <= src_data;
|
||||
src_toggle <= src_toggle + 1;
|
||||
src_data_reg <= src_data;
|
||||
src_data_gray <= binary_to_gray(src_data);
|
||||
src_toggle <= src_toggle + 1;
|
||||
end
|
||||
end
|
||||
|
||||
@@ -77,8 +82,8 @@ module cdc_adc_to_processing #(
|
||||
dst_data_gray[i] <= 0;
|
||||
end else begin
|
||||
if (i == 0) begin
|
||||
// Convert to gray code at domain crossing
|
||||
dst_data_gray[i] <= binary_to_gray(src_data_reg);
|
||||
// Sample registered Gray-code from source domain
|
||||
dst_data_gray[i] <= src_data_gray;
|
||||
end else begin
|
||||
dst_data_gray[i] <= dst_data_gray[i-1];
|
||||
end
|
||||
|
||||
@@ -5,8 +5,8 @@ module edge_detector_enhanced (
|
||||
output wire rising_falling_edge
|
||||
);
|
||||
|
||||
reg signal_in_prev;
|
||||
reg signal_in_prev2;
|
||||
(* ASYNC_REG = "TRUE" *) reg signal_in_prev;
|
||||
(* ASYNC_REG = "TRUE" *) reg signal_in_prev2;
|
||||
|
||||
always @(posedge clk or negedge reset_n) begin
|
||||
if (!reset_n) begin
|
||||
|
||||
@@ -133,6 +133,11 @@ wire clk_120m_dac_buf;
|
||||
wire ft601_clk_buf;
|
||||
wire sys_reset_n;
|
||||
wire sys_reset_120m_n; // Reset synchronized to clk_120m_dac domain
|
||||
wire sys_reset_ft601_n; // Reset synchronized to ft601_clk domain
|
||||
|
||||
// CDC: synchronized versions of async inputs for status_reg
|
||||
wire stm32_mixers_enable_100m; // stm32_mixers_enable sync'd to clk_100m
|
||||
wire ft601_txe_100m; // ft601_txe sync'd to clk_100m
|
||||
|
||||
// Transmitter internal signals
|
||||
wire [7:0] tx_chirp_data;
|
||||
@@ -214,6 +219,37 @@ always @(posedge clk_120m_dac_buf or negedge reset_n) begin
|
||||
end
|
||||
assign sys_reset_120m_n = reset_sync_120m[1];
|
||||
|
||||
// Reset synchronization (ft601_clk domain)
|
||||
// FT601 has its own asynchronous clock from the USB controller.
|
||||
// All FT601-domain registers need a properly synchronized reset.
|
||||
(* ASYNC_REG = "TRUE" *) reg [2:0] reset_sync_ft601; // 3-stage for better MTBF
|
||||
always @(posedge ft601_clk_buf or negedge reset_n) begin
|
||||
if (!reset_n) begin
|
||||
reset_sync_ft601 <= 3'b000;
|
||||
end else begin
|
||||
reset_sync_ft601 <= {reset_sync_ft601[1:0], 1'b1};
|
||||
end
|
||||
end
|
||||
assign sys_reset_ft601_n = reset_sync_ft601[2];
|
||||
|
||||
// CDC synchronizers for status_reg inputs (async -> clk_100m)
|
||||
// stm32_mixers_enable is an async GPIO; ft601_txe is on ft601_clk domain
|
||||
cdc_single_bit #(.STAGES(2)) cdc_mixers_en_status (
|
||||
.src_clk(clk_100m_buf), // Pseudo-source for async GPIO
|
||||
.dst_clk(clk_100m_buf),
|
||||
.reset_n(sys_reset_n),
|
||||
.src_signal(stm32_mixers_enable),
|
||||
.dst_signal(stm32_mixers_enable_100m)
|
||||
);
|
||||
|
||||
cdc_single_bit #(.STAGES(2)) cdc_ft601_txe_status (
|
||||
.src_clk(ft601_clk_buf),
|
||||
.dst_clk(clk_100m_buf),
|
||||
.reset_n(sys_reset_n),
|
||||
.src_signal(ft601_txe),
|
||||
.dst_signal(ft601_txe_100m)
|
||||
);
|
||||
|
||||
// ============================================================================
|
||||
// CLOCK DOMAIN CROSSING: TRANSMITTER (120 MHz) -> SYSTEM (100 MHz)
|
||||
// ============================================================================
|
||||
@@ -232,17 +268,38 @@ cdc_adc_to_processing #(
|
||||
.dst_valid(tx_current_chirp_sync_valid)
|
||||
);
|
||||
|
||||
// CDC for new_chirp_frame: single-bit 3-stage synchronizer
|
||||
// CDC for new_chirp_frame: toggle CDC (pulse on clk_120m -> pulse on clk_100m)
|
||||
// new_chirp_frame is a 1-cycle pulse on clk_120m_dac. A level synchronizer
|
||||
// at 100 MHz can miss it. Toggle CDC converts pulse -> level toggle,
|
||||
// synchronizes the toggle, then detects edges to recover the pulse.
|
||||
reg chirp_frame_toggle_120m;
|
||||
always @(posedge clk_120m_dac_buf or negedge sys_reset_120m_n) begin
|
||||
if (!sys_reset_120m_n)
|
||||
chirp_frame_toggle_120m <= 1'b0;
|
||||
else if (tx_new_chirp_frame)
|
||||
chirp_frame_toggle_120m <= ~chirp_frame_toggle_120m;
|
||||
end
|
||||
|
||||
wire chirp_frame_toggle_100m;
|
||||
cdc_single_bit #(
|
||||
.STAGES(3)
|
||||
) cdc_new_chirp_frame (
|
||||
.src_clk(clk_120m_dac_buf),
|
||||
.dst_clk(clk_100m_buf),
|
||||
.reset_n(sys_reset_n),
|
||||
.src_signal(tx_new_chirp_frame),
|
||||
.dst_signal(tx_new_chirp_frame_sync)
|
||||
.src_signal(chirp_frame_toggle_120m),
|
||||
.dst_signal(chirp_frame_toggle_100m)
|
||||
);
|
||||
|
||||
reg chirp_frame_toggle_100m_prev;
|
||||
always @(posedge clk_100m_buf or negedge sys_reset_n) begin
|
||||
if (!sys_reset_n)
|
||||
chirp_frame_toggle_100m_prev <= 1'b0;
|
||||
else
|
||||
chirp_frame_toggle_100m_prev <= chirp_frame_toggle_100m;
|
||||
end
|
||||
assign tx_new_chirp_frame_sync = chirp_frame_toggle_100m ^ chirp_frame_toggle_100m_prev;
|
||||
|
||||
// ============================================================================
|
||||
// RADAR TRANSMITTER INSTANTIATION
|
||||
// ============================================================================
|
||||
@@ -396,6 +453,7 @@ assign usb_cfar_valid = rx_cfar_valid;
|
||||
usb_data_interface usb_inst (
|
||||
.clk(clk_100m_buf),
|
||||
.reset_n(sys_reset_n),
|
||||
.ft601_reset_n(sys_reset_ft601_n), // FT601-domain synchronized reset
|
||||
|
||||
// Radar data inputs
|
||||
.range_profile(usb_range_profile),
|
||||
@@ -445,8 +503,8 @@ always @(posedge clk_100m_buf or negedge sys_reset_n) begin
|
||||
if (!sys_reset_n) begin
|
||||
status_reg <= 4'b0000;
|
||||
end else begin
|
||||
status_reg[0] <= stm32_mixers_enable; // Mixers enabled
|
||||
status_reg[1] <= ft601_txe; // USB TX ready
|
||||
status_reg[0] <= stm32_mixers_enable_100m; // Mixers enabled (CDC sync'd)
|
||||
status_reg[1] <= ft601_txe_100m; // USB TX ready (CDC sync'd)
|
||||
status_reg[2] <= rx_doppler_valid; // Data valid
|
||||
status_reg[3] <= tx_new_chirp_frame_sync; // New chirp frame (CDC-sync'd)
|
||||
end
|
||||
|
||||
@@ -84,11 +84,56 @@ wire new_chirp_pulse;
|
||||
wire new_elevation_pulse;
|
||||
wire new_azimuth_pulse;
|
||||
|
||||
// CDC: Synchronized versions of signals crossing clk_100m -> clk_120m_dac
|
||||
wire mixers_enable_120m; // stm32_mixers_enable sync'd to clk_120m_dac
|
||||
wire new_chirp_pulse_120m; // new_chirp_pulse (toggle CDC) in clk_120m_dac domain
|
||||
|
||||
// Chirp Control Signals
|
||||
wire [7:0] chirp_data;
|
||||
wire chirp_valid;
|
||||
wire chirp_sequence_done;
|
||||
|
||||
// Toggle CDC for new_chirp_pulse: clk_100m -> clk_120m_dac
|
||||
// Edge detector produces a 1-cycle pulse on clk_100m. A level synchronizer
|
||||
// would miss it (120/100 MHz ratio). Toggle CDC converts pulse to level toggle,
|
||||
// syncs the toggle, then detects edges on the destination side.
|
||||
reg chirp_toggle_100m;
|
||||
always @(posedge clk_100m or negedge reset_n) begin
|
||||
if (!reset_n)
|
||||
chirp_toggle_100m <= 1'b0;
|
||||
else if (new_chirp_pulse)
|
||||
chirp_toggle_100m <= ~chirp_toggle_100m;
|
||||
end
|
||||
|
||||
// Sync the toggle to clk_120m_dac domain
|
||||
wire chirp_toggle_120m;
|
||||
cdc_single_bit #(.STAGES(3)) cdc_chirp_toggle (
|
||||
.src_clk(clk_100m),
|
||||
.dst_clk(clk_120m_dac),
|
||||
.reset_n(reset_n),
|
||||
.src_signal(chirp_toggle_100m),
|
||||
.dst_signal(chirp_toggle_120m)
|
||||
);
|
||||
|
||||
// Detect edges on synchronized toggle to recover pulse in clk_120m domain
|
||||
reg chirp_toggle_120m_prev;
|
||||
always @(posedge clk_120m_dac or negedge reset_n) begin
|
||||
if (!reset_n)
|
||||
chirp_toggle_120m_prev <= 1'b0;
|
||||
else
|
||||
chirp_toggle_120m_prev <= chirp_toggle_120m;
|
||||
end
|
||||
assign new_chirp_pulse_120m = chirp_toggle_120m ^ chirp_toggle_120m_prev;
|
||||
|
||||
// Sync stm32_mixers_enable (async GPIO level) to clk_120m_dac domain
|
||||
cdc_single_bit #(.STAGES(3)) cdc_mixers_en_120m (
|
||||
.src_clk(clk_100m), // Treat as pseudo-source (GPIO is async)
|
||||
.dst_clk(clk_120m_dac),
|
||||
.reset_n(reset_n),
|
||||
.src_signal(stm32_mixers_enable),
|
||||
.dst_signal(mixers_enable_120m)
|
||||
);
|
||||
|
||||
// Enhanced STM32 Input Edge Detection with Debouncing
|
||||
edge_detector_enhanced chirp_edge (
|
||||
.clk(clk_100m),
|
||||
@@ -116,11 +161,11 @@ plfm_chirp_controller_enhanced plfm_chirp_inst (
|
||||
.clk_120m(clk_120m_dac),
|
||||
.clk_100m(clk_100m),
|
||||
.reset_n(reset_n),
|
||||
.new_chirp(new_chirp_pulse),
|
||||
.new_chirp(new_chirp_pulse_120m), // CDC-synchronized pulse in clk_120m domain
|
||||
.new_elevation(new_elevation_pulse),
|
||||
.new_azimuth(new_azimuth_pulse),
|
||||
.new_chirp_frame(new_chirp_frame),
|
||||
.mixers_enable(stm32_mixers_enable),
|
||||
.mixers_enable(mixers_enable_120m), // CDC-synchronized level in clk_120m domain
|
||||
.chirp_data(chirp_data),
|
||||
.chirp_valid(chirp_valid),
|
||||
.chirp_done(chirp_sequence_done),
|
||||
|
||||
@@ -236,6 +236,12 @@ always @(posedge clk or negedge reset_n) begin
|
||||
if (range_valid_in) begin
|
||||
in_bin_count <= in_bin_count + 1;
|
||||
|
||||
// Overflow guard: stop if we've consumed all input bins
|
||||
// Prevents corruption of downstream Doppler BRAM if matched
|
||||
// filter emits more than INPUT_BINS valid samples
|
||||
if (in_bin_count >= INPUT_BINS - 1) begin
|
||||
state <= ST_DONE;
|
||||
end else begin
|
||||
// Mode-specific sample processing
|
||||
case (decimation_mode)
|
||||
2'b00: begin // Simple decimation
|
||||
@@ -266,6 +272,7 @@ always @(posedge clk or negedge reset_n) begin
|
||||
end else begin
|
||||
group_sample_count <= group_sample_count + 1;
|
||||
end
|
||||
end // else (overflow guard)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# run_cdc_and_netlist.tcl
|
||||
# Opens the routed design and runs:
|
||||
# 1. report_cdc — detailed CDC analysis to investigate TIMING-9
|
||||
# 2. write_verilog — post-synthesis functional simulation netlist
|
||||
#
|
||||
# Usage: vivado -mode batch -source run_cdc_and_netlist.tcl
|
||||
|
||||
set project_dir "/home/jason-stone/PLFM_RADAR_work/vivado_project"
|
||||
set report_dir "${project_dir}/reports_impl"
|
||||
|
||||
# Open the routed checkpoint
|
||||
open_checkpoint ${project_dir}/aeris10_radar.runs/impl_1/radar_system_top_routed.dcp
|
||||
|
||||
# ============================================================================
|
||||
# 1. report_cdc — identify all CDC crossings and the TIMING-9 source
|
||||
# ============================================================================
|
||||
puts "INFO: Running report_cdc..."
|
||||
report_cdc -details -file ${report_dir}/cdc_report.txt
|
||||
|
||||
# ============================================================================
|
||||
# 2. Write post-synthesis functional simulation netlist
|
||||
# ============================================================================
|
||||
puts "INFO: Writing post-synthesis functional sim netlist..."
|
||||
|
||||
# Post-synthesis (from synth checkpoint) — simpler, no routing delays
|
||||
open_checkpoint ${project_dir}/aeris10_radar.runs/synth_1/radar_system_top.dcp
|
||||
write_verilog -force -mode funcsim \
|
||||
${project_dir}/sim/post_synth_funcsim.v
|
||||
|
||||
# Also write SDF for timing sim (from routed checkpoint)
|
||||
open_checkpoint ${project_dir}/aeris10_radar.runs/impl_1/radar_system_top_routed.dcp
|
||||
write_verilog -force -mode timesim \
|
||||
${project_dir}/sim/post_impl_timesim.v
|
||||
write_sdf -force \
|
||||
${project_dir}/sim/post_impl_timesim.sdf
|
||||
|
||||
puts "INFO: All reports and netlists generated."
|
||||
puts "INFO: CDC report: ${report_dir}/cdc_report.txt"
|
||||
puts "INFO: Post-synth sim: ${project_dir}/sim/post_synth_funcsim.v"
|
||||
puts "INFO: Post-impl sim: ${project_dir}/sim/post_impl_timesim.v"
|
||||
puts "INFO: SDF: ${project_dir}/sim/post_impl_timesim.sdf"
|
||||
File diff suppressed because it is too large
Load Diff
@@ -55,6 +55,7 @@ module tb_usb_data_interface;
|
||||
usb_data_interface uut (
|
||||
.clk (clk),
|
||||
.reset_n (reset_n),
|
||||
.ft601_reset_n (reset_n), // In TB, share same reset for both domains
|
||||
.range_profile (range_profile),
|
||||
.range_valid (range_valid),
|
||||
.doppler_real (doppler_real),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
module usb_data_interface (
|
||||
input wire clk, // Main clock (100MHz recommended)
|
||||
input wire reset_n,
|
||||
input wire ft601_reset_n, // FT601-domain synchronized reset
|
||||
|
||||
// Radar data inputs
|
||||
input wire [31:0] range_profile,
|
||||
@@ -67,7 +68,40 @@ reg ft601_data_oe; // Output enable for bidirectional data bus
|
||||
(* ASYNC_REG = "TRUE" *) reg [1:0] doppler_valid_sync;
|
||||
(* ASYNC_REG = "TRUE" *) reg [1:0] cfar_valid_sync;
|
||||
|
||||
// Synchronized data captures (registered in ft601_clk_in domain)
|
||||
// Delayed versions of sync[1] for proper edge detection
|
||||
reg range_valid_sync_d;
|
||||
reg doppler_valid_sync_d;
|
||||
reg cfar_valid_sync_d;
|
||||
|
||||
// Holding registers: data captured in SOURCE domain (clk_100m) when valid
|
||||
// asserts, then read by ft601 domain after synchronized valid edge.
|
||||
// This is safe because the data is stable for the entire time the valid
|
||||
// pulse is being synchronized (2+ ft601_clk cycles).
|
||||
reg [31:0] range_profile_hold;
|
||||
reg [15:0] doppler_real_hold;
|
||||
reg [15:0] doppler_imag_hold;
|
||||
reg cfar_detection_hold;
|
||||
|
||||
// Source-domain holding registers (clk domain)
|
||||
always @(posedge clk or negedge reset_n) begin
|
||||
if (!reset_n) begin
|
||||
range_profile_hold <= 32'd0;
|
||||
doppler_real_hold <= 16'd0;
|
||||
doppler_imag_hold <= 16'd0;
|
||||
cfar_detection_hold <= 1'b0;
|
||||
end else begin
|
||||
if (range_valid)
|
||||
range_profile_hold <= range_profile;
|
||||
if (doppler_valid) begin
|
||||
doppler_real_hold <= doppler_real;
|
||||
doppler_imag_hold <= doppler_imag;
|
||||
end
|
||||
if (cfar_valid)
|
||||
cfar_detection_hold <= cfar_detection;
|
||||
end
|
||||
end
|
||||
|
||||
// FT601-domain captured data (sampled from holding regs on sync'd edge)
|
||||
reg [31:0] range_profile_cap;
|
||||
reg [15:0] doppler_real_cap;
|
||||
reg [15:0] doppler_imag_cap;
|
||||
@@ -77,43 +111,53 @@ wire range_valid_ft;
|
||||
wire doppler_valid_ft;
|
||||
wire cfar_valid_ft;
|
||||
|
||||
always @(posedge ft601_clk_in or negedge reset_n) begin
|
||||
if (!reset_n) begin
|
||||
always @(posedge ft601_clk_in or negedge ft601_reset_n) begin
|
||||
if (!ft601_reset_n) begin
|
||||
range_valid_sync <= 2'b00;
|
||||
doppler_valid_sync <= 2'b00;
|
||||
cfar_valid_sync <= 2'b00;
|
||||
range_valid_sync_d <= 1'b0;
|
||||
doppler_valid_sync_d <= 1'b0;
|
||||
cfar_valid_sync_d <= 1'b0;
|
||||
range_profile_cap <= 32'd0;
|
||||
doppler_real_cap <= 16'd0;
|
||||
doppler_imag_cap <= 16'd0;
|
||||
cfar_detection_cap <= 1'b0;
|
||||
end else begin
|
||||
// Synchronize valid strobes
|
||||
// Synchronize valid strobes (2-stage sync chain)
|
||||
range_valid_sync <= {range_valid_sync[0], range_valid};
|
||||
doppler_valid_sync <= {doppler_valid_sync[0], doppler_valid};
|
||||
cfar_valid_sync <= {cfar_valid_sync[0], cfar_valid};
|
||||
|
||||
// Capture data on rising edge of synchronized valid
|
||||
if (range_valid_sync[0] && !range_valid_sync[1])
|
||||
range_profile_cap <= range_profile;
|
||||
if (doppler_valid_sync[0] && !doppler_valid_sync[1]) begin
|
||||
doppler_real_cap <= doppler_real;
|
||||
doppler_imag_cap <= doppler_imag;
|
||||
// Delayed version of sync[1] for edge detection
|
||||
range_valid_sync_d <= range_valid_sync[1];
|
||||
doppler_valid_sync_d <= doppler_valid_sync[1];
|
||||
cfar_valid_sync_d <= cfar_valid_sync[1];
|
||||
|
||||
// Capture data on rising edge of FULLY SYNCHRONIZED valid (sync[1])
|
||||
// Data in holding regs is stable by the time sync[1] rises (2+ cycles)
|
||||
if (range_valid_sync[1] && !range_valid_sync_d)
|
||||
range_profile_cap <= range_profile_hold;
|
||||
if (doppler_valid_sync[1] && !doppler_valid_sync_d) begin
|
||||
doppler_real_cap <= doppler_real_hold;
|
||||
doppler_imag_cap <= doppler_imag_hold;
|
||||
end
|
||||
if (cfar_valid_sync[0] && !cfar_valid_sync[1])
|
||||
cfar_detection_cap <= cfar_detection;
|
||||
if (cfar_valid_sync[1] && !cfar_valid_sync_d)
|
||||
cfar_detection_cap <= cfar_detection_hold;
|
||||
end
|
||||
end
|
||||
|
||||
// Rising-edge detect on synchronized valid (pulse in ft601_clk_in domain)
|
||||
assign range_valid_ft = range_valid_sync[0] && !range_valid_sync[1];
|
||||
assign doppler_valid_ft = doppler_valid_sync[0] && !doppler_valid_sync[1];
|
||||
assign cfar_valid_ft = cfar_valid_sync[0] && !cfar_valid_sync[1];
|
||||
// Rising-edge detect on FULLY SYNCHRONIZED valid (sync[1], not sync[0])
|
||||
// This provides full 2-stage metastability protection before use.
|
||||
assign range_valid_ft = range_valid_sync[1] && !range_valid_sync_d;
|
||||
assign doppler_valid_ft = doppler_valid_sync[1] && !doppler_valid_sync_d;
|
||||
assign cfar_valid_ft = cfar_valid_sync[1] && !cfar_valid_sync_d;
|
||||
|
||||
// FT601 data bus direction control
|
||||
assign ft601_data = ft601_data_oe ? ft601_data_out : 32'hzzzz_zzzz;
|
||||
|
||||
always @(posedge ft601_clk_in or negedge reset_n) begin
|
||||
if (!reset_n) begin
|
||||
always @(posedge ft601_clk_in or negedge ft601_reset_n) begin
|
||||
if (!ft601_reset_n) begin
|
||||
current_state <= IDLE;
|
||||
byte_counter <= 0;
|
||||
ft601_data_out <= 0;
|
||||
@@ -248,8 +292,8 @@ ODDR #(
|
||||
`else
|
||||
// Simulation: behavioral clock forwarding
|
||||
reg ft601_clk_out_sim;
|
||||
always @(posedge ft601_clk_in or negedge reset_n) begin
|
||||
if (!reset_n)
|
||||
always @(posedge ft601_clk_in or negedge ft601_reset_n) begin
|
||||
if (!ft601_reset_n)
|
||||
ft601_clk_out_sim <= 1'b0;
|
||||
else
|
||||
ft601_clk_out_sim <= 1'b1;
|
||||
|
||||
Reference in New Issue
Block a user