1`timescale 1ns / 1ps
2/*
3 * This software is Copyright (c) 2016 Denis Burykin
4 * [denis_burykin yahoo com], [denis-burykin2014 yandex ru]
5 * and it is hereby released to the general public under the following terms:
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted.
8 *
9 */
10
11
12// 2-stage FF synchronizer
13module sync_sig #(
14	parameter INIT = 0,
15	// if input signal is 1-2 clk cycles
16	// and CLK1 is set, result would be 1 cycle long
17	// * if input is longer than 2 cycles, it would produce extra result
18	// * if less than 1 cycle, there might be no result (consider usage of sync_short_sig)
19	parameter CLK1 = 0
20	)(
21	input sig,
22	input clk,
23	//input en,
24	output out
25	);
26
27	(* SHREG_EXTRACT="NO" *)
28	reg [1:0] ff = {2{INIT[0]}};
29	assign out = ff[1];
30
31	if (CLK1) begin
32
33		always @(posedge clk)
34			if (ff[1] ^ INIT[0])
35				ff[1:0] <= {2{INIT[0]}};
36			else
37				ff[1:0] <= { ff[0], sig };
38
39	end else begin // ! CLK1
40
41		always @(posedge clk)
42			ff[1:0] <= { ff[0], sig };
43
44	end
45
46endmodule
47
48
49// 3-stage FF synchronizer
50module sync_sig3(
51	input sig,
52	input clk,
53	output out
54	);
55
56	(* SHREG_EXTRACT="NO" *)
57	reg [2:0] ff = 0;
58	assign out = ff[2];
59
60	always @(posedge clk)
61		ff[2:0] <= { ff[1:0], sig };
62
63endmodule
64
65/*
66// For synchronizing short-duration signals (less than clk cycle),
67// 2-stage FF synchronizer is prepended with async register
68module sync_short_sig #(
69	parameter INIT = 0,
70	parameter CLK1 = 0
71	)(
72	input sig,
73	input clk,
74	output out
75	);
76
77	// There's no such registers in Spartan 6 architecture,
78	// with a warning tools produce an equvalent item from 3 parts
79	reg async_r = INIT[0];
80
81	always @(posedge clk or posedge sig)
82		if (sig)
83			async_r <= ~INIT[0];
84		else
85			if (out)
86				async_r <= INIT[0];
87
88	sync_sig #(.INIT(INIT), .CLK1(CLK1)) sync(.sig(async_r), .clk(clk), .out(out));
89
90endmodule
91*/
92
93// Any frequency relation between wr_clk and rd_clk
94// 'out' duration is 1 clock cycle (repeats after 'busy' deasserts)
95module sync_pulse (
96	input wr_clk,
97	input sig,
98	output busy,
99
100	input rd_clk,
101	// 'out' must be OK in terms of metastability
102	output out
103	);
104
105	reg flag_wr = 0;
106	always @(posedge wr_clk) flag_wr <= flag_wr ^ (sig & ~busy);
107
108	(* SHREG_EXTRACT="NO" *)
109	reg [2:0] sync_rd = 3'b000;
110	always @(posedge rd_clk) sync_rd <= {sync_rd[1:0], flag_wr};
111
112	(* SHREG_EXTRACT="NO" *)
113	reg [1:0] sync_wr = 2'b00;
114	always @(posedge wr_clk) sync_wr <= {sync_wr[0], sync_rd[2]};
115
116	assign busy = flag_wr ^ sync_wr[1];
117	assign out = sync_rd[2] ^ sync_rd[1];
118
119endmodule
120
121
122// Any frequency relation between wr_clk and rd_clk
123// 'out' duration is 1 clock cycle (repeats after 'busy' deasserts)
124// 3 FFs
125module sync_pulse3 (
126	input wr_clk,
127	input sig,
128	output busy,
129
130	input rd_clk,
131	// 'out' must be OK in terms of metastability
132	output out
133	);
134
135	reg flag_wr = 0;
136	always @(posedge wr_clk) flag_wr <= flag_wr ^ (sig & ~busy);
137
138	(* SHREG_EXTRACT="NO" *)
139	reg [3:0] sync_rd = 4'b0000;
140	always @(posedge rd_clk) sync_rd <= {sync_rd[2:0], flag_wr};
141
142	(* SHREG_EXTRACT="NO" *)
143	reg [2:0] sync_wr = 3'b000;
144	always @(posedge wr_clk) sync_wr <= {sync_wr[1:0], sync_rd[3]};
145
146	assign busy = flag_wr ^ sync_wr[2];
147	assign out = sync_rd[3] ^ sync_rd[2];
148
149endmodule
150
151/*
152// Any frequency relation between wr_clk and rd_clk
153module sync_ack(
154	input wr_clk,
155	input sig,
156	output busy, // asserts on the next cycle
157
158	input rd_clk,
159	output out,
160	input done
161	);
162
163	reg flag_wr = 0;
164	always @(posedge wr_clk) flag_wr <= flag_wr ^ (sig & ~busy);
165
166	(* SHREG_EXTRACT="NO" *)
167	reg [2:0] sync_rd = 3'b0;
168	always @(posedge rd_clk)
169		if (~out | done)
170			sync_rd <= {sync_rd[1:0], flag_wr};
171
172	(* SHREG_EXTRACT="NO" *)
173	reg [1:0] sync_wr = 2'b0;
174	always @(posedge wr_clk)
175		if (out | done | done_r)
176			sync_wr <= {sync_wr[0], sync_rd[2]};
177
178	assign out = sync_rd[2] ^ sync_rd[1];
179	assign busy = flag_wr ^ sync_wr[1];
180
181	reg done_r = 0;
182	always @(posedge rd_clk)
183		if (out & done)
184			done_r <= 1;
185		else if (done_r)
186			done_r <= 0;
187
188endmodule
189*/
190/*
191// sig is active for no more than 1 cycle
192module pulse1(
193	input CLK,
194	input sig,
195	output out
196	);
197
198	reg done = 0;
199	always @(posedge CLK)
200		done <= sig;
201
202	assign out = sig & ~done;
203
204endmodule
205*/
206
207