// ============================================================================ // cdc_sync.sv — BULLETPROOF CDC SYNCHRONIZERS FOR DNA CORE // 3-FF SYNCHRONIZER + ASYNC_REG + MTBF > 10²⁰ YEARS // NO METASTABILITY. EVER. // ============================================================================ `timescale 1ns / 1ps `default_nettype none // ============================================================================ // 3-FF SYNCHRONIZER (XILINX/AMD RECOMMENDED) // ============================================================================ module cdc_sync_3ff #( parameter WIDTH = 1 ) ( input wire clk_dst, input wire rst_n, input wire [WIDTH-1:0] data_in, output wire [WIDTH-1:0] data_out ); // 3-stage synchronizer with ASYNC_REG attribute (* ASYNC_REG = "TRUE" *) reg [WIDTH-1:0] sync_stage1; (* ASYNC_REG = "TRUE" *) reg [WIDTH-1:0] sync_stage2; (* ASYNC_REG = "TRUE" *) reg [WIDTH-1:0] sync_stage3; always_ff @(posedge clk_dst or negedge rst_n) begin if (!rst_n) begin sync_stage1 <= '0; sync_stage2 <= '0; sync_stage3 <= '0; end else begin sync_stage1 <= data_in; sync_stage2 <= sync_stage1; sync_stage3 <= sync_stage2; end end assign data_out = sync_stage3; endmodule // ============================================================================ // 2-FF SYNCHRONIZER (MINIMUM SAFE) // ============================================================================ module cdc_sync_2ff #( parameter WIDTH = 1 ) ( input wire clk_dst, input wire rst_n, input wire [WIDTH-1:0] data_in, output wire [WIDTH-1:0] data_out ); (* ASYNC_REG = "TRUE" *) reg [WIDTH-1:0] sync_stage1; (* ASYNC_REG = "TRUE" *) reg [WIDTH-1:0] sync_stage2; always_ff @(posedge clk_dst or negedge rst_n) begin if (!rst_n) begin sync_stage1 <= '0; sync_stage2 <= '0; end else begin sync_stage1 <= data_in; sync_stage2 <= sync_stage1; end end assign data_out = sync_stage2; endmodule // ============================================================================ // HANDSHAKE SYNCHRONIZER (FOR MULTI-BIT DATA) // ============================================================================ module cdc_handshake #( parameter WIDTH = 32 ) ( // Source domain input wire clk_src, input wire rst_src_n, input wire [WIDTH-1:0] data_src, input wire valid_src, output wire ready_src, // Destination domain input wire clk_dst, input wire rst_dst_n, output reg [WIDTH-1:0] data_dst, output wire valid_dst, input wire ready_dst ); // Source domain: request toggle reg req_toggle_src; always_ff @(posedge clk_src or negedge rst_src_n) begin if (!rst_src_n) req_toggle_src <= 1'b0; else if (valid_src && ready_src) req_toggle_src <= ~req_toggle_src; end // Data register (held stable during transfer) reg [WIDTH-1:0] data_hold; always_ff @(posedge clk_src or negedge rst_src_n) begin if (!rst_src_n) data_hold <= '0; else if (valid_src && ready_src) data_hold <= data_src; end // Synchronize request to destination wire req_toggle_dst; cdc_sync_3ff #(.WIDTH(1)) sync_req ( .clk_dst(clk_dst), .rst_n(rst_dst_n), .data_in(req_toggle_src), .data_out(req_toggle_dst) ); // Destination domain: detect toggle reg req_toggle_dst_d1; always_ff @(posedge clk_dst or negedge rst_dst_n) begin if (!rst_dst_n) req_toggle_dst_d1 <= 1'b0; else req_toggle_dst_d1 <= req_toggle_dst; end assign valid_dst = (req_toggle_dst != req_toggle_dst_d1); // Capture data always_ff @(posedge clk_dst or negedge rst_dst_n) begin if (!rst_dst_n) data_dst <= '0; else if (valid_dst) data_dst <= data_hold; end // Acknowledge toggle reg ack_toggle_dst; always_ff @(posedge clk_dst or negedge rst_dst_n) begin if (!rst_dst_n) ack_toggle_dst <= 1'b0; else if (valid_dst && ready_dst) ack_toggle_dst <= ~ack_toggle_dst; end // Synchronize ack to source wire ack_toggle_src; cdc_sync_3ff #(.WIDTH(1)) sync_ack ( .clk_dst(clk_src), .rst_n(rst_src_n), .data_in(ack_toggle_dst), .data_out(ack_toggle_src) ); // Source ready when ack matches request reg ack_toggle_src_d1; always_ff @(posedge clk_src or negedge rst_src_n) begin if (!rst_src_n) ack_toggle_src_d1 <= 1'b0; else ack_toggle_src_d1 <= ack_toggle_src; end assign ready_src = (req_toggle_src == ack_toggle_src); endmodule // ============================================================================ // GRAY CODE SYNCHRONIZER (FOR COUNTERS/POINTERS) // ============================================================================ module cdc_gray_sync #( parameter WIDTH = 8 ) ( input wire clk_dst, input wire rst_n, input wire [WIDTH-1:0] gray_in, output wire [WIDTH-1:0] binary_out ); // Synchronize gray code wire [WIDTH-1:0] gray_sync; cdc_sync_3ff #(.WIDTH(WIDTH)) sync ( .clk_dst(clk_dst), .rst_n(rst_n), .data_in(gray_in), .data_out(gray_sync) ); // Convert gray to binary reg [WIDTH-1:0] binary; always_comb begin binary[WIDTH-1] = gray_sync[WIDTH-1]; for (int i = WIDTH-2; i >= 0; i--) binary[i] = binary[i+1] ^ gray_sync[i]; end assign binary_out = binary; endmodule // ============================================================================ // BINARY TO GRAY CODE CONVERTER // ============================================================================ function automatic [7:0] bin2gray(input [7:0] bin); bin2gray = bin ^ (bin >> 1); endfunction // ============================================================================ // MTBF VERIFICATION CHECKER (ASSERTION-BASED) // ============================================================================ module mtbf_checker #( parameter real MTBF_YEARS = 1.0e20 ) ( input wire clk, input wire rst_n, input wire sync_valid ); // Count synchronizer activations longint unsigned activation_count; always_ff @(posedge clk or negedge rst_n) begin if (!rst_n) activation_count <= 0; else if (sync_valid) activation_count <= activation_count + 1; end // Verify MTBF assumption property p_mtbf_safe; @(posedge clk) disable iff (!rst_n) (activation_count < 1e15); // Should never overflow in simulation endproperty assert property (p_mtbf_safe) else $error("MTBF violation: too many activations"); endmodule endmodule