//---------------------------------------------------
//------------- BASIC SYNCHRONIZER ------------------
//---------------------------------------------------
module basicSynchronizer #
(	parameter Length = 2)
(	
	input Rst_i,	
	input Clk_i,
	input D_i,
	output D_o
);

	reg [Length-1 : 0] dReg;

	always @ (posedge Rst_i or posedge Clk_i)
		if (Rst_i)
			dReg <= 0;
		else
			dReg <= {dReg[Length-2 : 0], D_i};
	
	assign D_o = dReg[Length - 1];
	
endmodule

//---------------------------------------------------
//--------- EDGE-DETECTING SYNCHRONIZER -------------
//---------------------------------------------------

module edgeDetectingSynchronizer #
( 
	parameter Length = 2,
	parameter EdgeType = "rising"
)
(		
	input Rst_i,	
	input Clk_i,
	input D_i,
	output D_o
);

	wire basicSyncOut;
	reg outReg;

	basicSynchronizer # (.Length(Length)) 
	basicSynch (
		.Rst_i(Rst_i),
		.Clk_i(Clk_i),
		.D_i(D_i),
		.D_o(basicSyncOut)
	);
		
	always @ (posedge Rst_i or posedge Clk_i)
		if (Rst_i)
			outReg <= 0;
		else
			outReg <= basicSyncOut;
			
	generate 
		if (EdgeType == "rising")
			assign D_o = (basicSyncOut & (~outReg));
		else
			assign D_o = ((~basicSyncOut) & (outReg));
	endgenerate
	
endmodule


//--------------------------------------------------------------------------
//------------- FAST-TO-SLOW FREQUENCY DOMAIN SYNCHRONIZER -----------------
//--------------------------------------------------------------------------
module fastToSlowSynch
(		
	input Rst_i,	
	input Clk_i,
	input D_i,
	output D_o
);

	reg din_r, dout_r, rsti;
	
	wire rsts = (Rst_i || rsti);
	
	always @ (posedge rsts or posedge D_i)
		if (rsts)
			din_r <= 0;
		else
			din_r <= 1;
			
	always @ (posedge Rst_i or posedge Clk_i)
		if (Rst_i)
			begin
				dout_r <= 0;
				rsti <= 0;
			end
		else 
			if (din_r)
				begin
					dout_r <= 1;
					rsti <= 1;
				end
			else if (dout_r)
				begin
					dout_r <= 0;
					rsti <= 0;
				end

	assign D_o = dout_r;	
	
endmodule

//--------------------------------------------------------------------------
//------------- FAST-TO-SLOW FREQUENCY DOMAIN SYNCHRONIZER -----------------
//--------------------------------------------------------------------------
module fastToSlowSynchPosPulseStretch #
(
	parameter StretchInClock = 2,
	parameter SyncLength = 2
)
(		
	input Rst_i,
	input D_i,
	output D_o,
	input ClkIn_i,
	input ClkOut_i
);

	reg dStretched;
	generate 
		if (StretchInClock > 2)
			begin
				reg [StretchInClock-2:0] dShReg;
				always @ (posedge ClkIn_i or posedge Rst_i)
					if (Rst_i)
						begin
							dShReg <= 0;
							dStretched <= 0;
						end
					else
						begin
							dShReg <= {dShReg[StretchInClock-3:0], D_i};
							dStretched <= (D_i || (dShReg != 0)) ? 1 : 0;
						end
			end
		else if (StretchInClock == 2)
			begin
				reg dReg;
				always @ (posedge ClkIn_i or posedge Rst_i)
					if (Rst_i)
						begin
							dReg <= 0;
							dStretched <= 0;
						end
					else
						begin
							dReg <= D_i;
							dStretched <= dReg | D_i;
						end
			end
	endgenerate
	
	edgeDetectingSynchronizer #
	( 
		.Length(SyncLength),
		.EdgeType("rising")
	)
	edgeSyncInst
	(		
		.Rst_i(Rst_i),
		.Clk_i(ClkOut_i),
		.D_i(dStretched),
		.D_o(D_o)
	);	
	
endmodule

