// ----------------------------------------------------------------------- // // Copyright 2016 H. Peter Anvin - All Rights Reserved // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, // Boston MA 02110-1301, USA; either version 2 of the License, or // (at your option) any later version; incorporated herein by reference. // // ----------------------------------------------------------------------- // // Synchronize data from different clock domains. This is pretty trivial // stuff in theory; most of the complexity comes from giving hints // to the synthesizer. Good reason to make this a parameterized module. // (* altera_attribute = "-name synchronizer_identification FORCED; -name auto_shift_register_recognition OFF; -name global_signal OFF" *) module synchronizer(reset, clk, enable, d, q); parameter width = 1; // Minimum 1 parameter stages = 2; // Minimum 2 parameter stabilized = 0; // Used to disable D104 warning input reset; input clk; input enable; // If 0, hold the output constant input [width-1:0] d; output [width-1:0] q; // Inputs to these modules are inherently asynchronous, that is the // whole point. Let the timing analyzer know that is okay. // We define stage[0] separately as d_q to enable separate attributes. // If the stabilizer is enabled, also there is no need to warn about // bus skew (design rule D104). // I used a generate if else statement here, but it seems to have // led to the completely wrong result... (* altera_attribute = "-name disable_da_rule \"D104\" ; -name cut on -from * ; -name sdc_statement \"set_false_path -to [get_keepers {*|synchronizer:*|d_q[*]}]\"" *) reg [width-1:0] d_q = {width{1'b0}}; reg [width-1:0] stage[1:stages-1]; wire [stages-1:0] stage_enable = {enable, {(stages-1){1'b1}}}; assign q = stage[stages-1]; integer s; initial for (s = 1; s < stages; s = s + 1) stage[s] = {width{1'b0}}; always @(posedge clk) if (reset) d_q <= {width{1'b0}}; else // if (stage_enable[0]) d_q <= d; always @(posedge clk) if (reset) stage[1] <= {width{1'b0}}; else // if (stage_enable[1]) stage[1] <= d_q; genvar i; generate for (i = 2; i < stages; i = i + 1) begin: gen_stages always @(posedge clk) if (reset) stage[i] <= {width{1'b0}}; else // if (stage_enable[i]) stage[i] <= stage[i-1]; end endgenerate endmodule // // Stabilize the result of crossing a bus across asynchronous clock domains. // This is an inherently unsafe operation, because there is no guarantee // that even when synchronized their values will be latched in the same // cycle. However, if the outputs change slowly *and* an extra 2 // target cycle of latency is acceptable, then we can compare the outputs // with the previous ones and save the result only if doing so is safe. // // This makes no sense to use with width = 1, so the bus width should // always be specified. This is intended to be connected to the output // of a synchronizer, it does not itself include the synchronizer chain. // module stabilizer(reset, clk, enable, d, q); parameter width = 1; // Minimum useful = 2 input reset; input clk; input enable; // if 0, hold output value constant input [width-1:0] d; output [width-1:0] q; reg [width-1:0] d_q = {width{1'b0}}; // One cycle delayed input reg [width-1:0] q_q = {width{1'b0}}; // Latched output assign q = q_q; wire d_stable = ~|(d ^ d_q); wire d_valid = d_stable & enable; always @(posedge clk) if (reset) d_q <= {width{1'b0}}; else d_q <= d; always @(posedge clk) if (reset) q_q <= {width{1'b0}}; else begin if (d_valid) q_q <= d_q; end endmodule // // General synchronizer with optional stabilizer // module synchronize(reset, clk, enable, d, q); parameter width = 1; // Minimum 1 parameter stages = 2; // Minimum 2 parameter stabilize = 1; // Add stabilizer if necessary parameter bypass = 0; // Add stabilizer bypass // "stabilized" indicates if our output is stabilized one way or another. // "stabilizer" indicates if we need to instantiate a physical stabilizer. parameter stabilized = stabilize || (width <= 1); parameter stabilizer = stabilize && (width > 1); input tri0 reset; input clk; input tri1 enable; // If 0, hold the output constant input [width-1:0] d; output [width-1:0] q; wire [width-1:0] sync_q; wire sync_enable = stabilizer ? 1'b1 : enable; reg s_reset = 1'b1; always @(posedge clk) s_reset <= reset; synchronizer #(.width(width), .stages(stages), .stabilized(stabilized)) synchronizer(.d(d), .q(sync_q), .enable(sync_enable), .reset(s_reset), .clk(clk)); generate if (stabilizer) stabilizer #(.width(width)) stabilizer(.d(sync_q), .q(q), .enable(enable), .reset(s_reset), .clk(clk)); else assign q = sync_q; endgenerate endmodule // synchronize