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//
13// Clock Domain Crossing Register
14//
15// * assumes frequency relation: wr_clk <= rd_clk <= wr_clk X 2
16//   (write frequency is less or equal)
17//
18// *********************************************************
19
20module cdc_reg #(
21	parameter WIDTH = -1
22	)(
23	input wr_clk,
24	input [WIDTH-1:0] din,
25	input wr_en,
26	output reg full = 0,
27
28	input rd_clk,
29	output reg [WIDTH-1:0] dout = {WIDTH{1'b0}},
30	input rd_en,
31	output empty
32	);
33
34	always @(posedge wr_clk) begin
35		if (~full) begin
36			if (wr_en) begin
37				dout <= din;
38				full <= 1;
39			end
40		end
41		else if (rd_en_sync)
42			full <= 0;
43	end
44
45	sync_sig sync_full(.sig(full), .clk(rd_clk), .out(full_sync));
46
47	sync_short_sig #(.CLK1(1)) sync_rd_en(.sig(rd_en), .clk(wr_clk), .out(rd_en_sync));
48
49	// EMPTY considerations.
50	// must react on rd_en in 1 cycle - requires to run on rd_clk clock
51	// after read, consider FULL flag synchronization
52	localparam	EMPTY_STATE_INIT = 0,
53					EMPTY_STATE_CAN_READ = 1,
54					EMPTY_STATE_READ_COMPLETE = 2;
55
56	(* FSM_EXTRACT="true" *)
57	reg [1:0] empty_state = EMPTY_STATE_INIT;
58
59	always @(posedge rd_clk)
60		case (empty_state)
61		EMPTY_STATE_INIT:
62			if (full_sync)
63				empty_state <= EMPTY_STATE_CAN_READ;
64
65		EMPTY_STATE_CAN_READ:
66			if (rd_en)
67				empty_state <= EMPTY_STATE_READ_COMPLETE;
68
69		EMPTY_STATE_READ_COMPLETE:
70			if (~full_sync)
71				empty_state <= EMPTY_STATE_INIT;
72
73		endcase
74
75	assign empty = empty_state == EMPTY_STATE_CAN_READ ? 1'b0 : 1'b1;
76
77
78endmodule
79
80
81// *********************************************************
82//
83// Clock Domain Crossing Register - Improved version
84//
85// * Any frequency relation
86// * For good throughput, use a FIFO
87//
88// *********************************************************
89
90module xdc_reg #(
91	parameter WIDTH = -1
92	)(
93	input wr_clk,
94	input [WIDTH-1:0] din,
95	input wr_en,
96	output reg full = 0,
97
98	input rd_clk,
99	output reg [WIDTH-1:0] dout = {WIDTH{1'b0}},
100	input rd_en,
101	output empty
102	);
103
104	always @(posedge wr_clk) begin
105		if (~full) begin
106			if (wr_en) begin
107				dout <= din;
108				full <= 1;
109			end
110		end
111		else if (rd_en_sync)
112			full <= 0;
113	end
114
115	sync_pulse sync_full(.wr_clk(wr_clk), .sig(full), .busy(), .rd_clk(rd_clk), .out(full_sync));
116
117	sync_pulse sync_rd_en(.wr_clk(rd_clk), .sig(rd_en), .busy(), .rd_clk(wr_clk), .out(rd_en_sync));
118
119	localparam	EMPTY_STATE_CAN_READ = 0,
120					EMPTY_STATE_READ_COMPLETE = 1;
121
122	//(* FSM_EXTRACT="true" *)
123	reg empty_state = EMPTY_STATE_CAN_READ;
124
125	always @(posedge rd_clk)
126		case (empty_state)
127		EMPTY_STATE_CAN_READ:
128			if (rd_en & full_sync)
129				empty_state <= EMPTY_STATE_READ_COMPLETE;
130
131		EMPTY_STATE_READ_COMPLETE:
132			if (~full_sync)
133				empty_state <= EMPTY_STATE_CAN_READ;
134
135		endcase
136
137	assign empty = empty_state == EMPTY_STATE_CAN_READ & full_sync ? 1'b0 : 1'b1;
138
139endmodule
140