//------------------------------------------------------------------------------
//
//  xil_dvi_rx.v : xilinx spartan3a tmds recieve module
//
//  LICENSE : "as-is"
//  TakeshiNagashima(T.NG) candylogic@gmail.com
//------------------------------------------------------------------------------
//  2009/mar/09 release 1.0a dvi(tmds) display test
//      /jul/21 release 1.0b signal rename
//
//------------------------------------------------------------------------------
//
//  refer to
//
//  DDWG Digital Display working Group
//  Digital Visual Interface Revision 1.0 02/April/1999
//  http://www.ddwg.org
//  See FAQS and Adopter's Agreement.
//
//  This code implemented it according to DDWG DVI Revision 1.0. 
//  As for the TMDS encoding and decoding algorithm, DDWG owns a right.
//
//------------------------------------------------------------------------------

module xil_dvi_rx(
	input			DVI_RX0_N,				// in    [RX] RX0-N (CML)
	input			DVI_RX0_P,				// in    [RX] RX0-P (CML)
	input			DVI_RX1_N,				// in    [RX] RX1-N (CML)
	input			DVI_RX1_P,				// in    [RX] RX1-P (CML)
	input			DVI_RX2_N,				// in    [RX] RX2-N (CML)
	input			DVI_RX2_P,				// in    [RX] RX2-P (CML)
	input			DVI_RXC_N,				// in    [RX] RXC-N (CML)
	input			DVI_RXC_P,				// in    [RX] RXC-P (CML)

	output	[7:0]	RX_RED,					// out   [RX] [7:0] red
	output	[7:0]	RX_GRN,					// out   [RX] [7:0] green
	output	[7:0]	RX_BLU,					// out   [RX] [7:0] blue
	output			RX_HS,					// out   [RX] hsync
	output			RX_VS,					// out   [RX] vsync
	output			RX_C0,					// out   [RX] c0
	output			RX_C1,					// out   [RX] c1
	output			RX_C2,					// out   [RX] c2
	output			RX_C3,					// out   [RX] c3
	output			RX_DE,					// out   [RX] de

	output			CLK_LOCK,				// out   [RX] test sinal
	output			CLKx10,					// out   [RX] test sinal
	output			CLK,					// out   [RX] clock
	input			RESET_N					// in    [RX] #reset
);

//--------------------------------------------------------------
//  override parameter

//--------------------------------------------------------------
//  local parameter

//--------------------------------------------------------------
//	signal

	wire	RX0_IN;
	wire	RX1_IN;
	wire	RX2_IN;
	wire	CLK_IN;
	wire	CLK_OUT;

	wire	clk_x10;
	wire	dcm_locked;

	wire	sys_rst_n;
	reg		[4:0] sys_rst_n_r;

	wire	rx_req;

	reg		[3:0] rx_req_r;
	wire	[3:0] rx_req_w;

	reg		[11:0] rx0_r;
	reg		[11:0] rx1_r;
	reg		[11:0] rx2_r;
	wire	[11:0] rx0_w;
	wire	[11:0] rx1_w;
	wire	[11:0] rx2_w;

	reg		[9:0] rx0_out_r;
	reg		[9:0] rx1_out_r;
	reg		[9:0] rx2_out_r;
	wire	[9:0] rx0_out_w;
	wire	[9:0] rx1_out_w;
	wire	[9:0] rx2_out_w;

	reg		[9:0] ch0_in_r;
	reg		[9:0] ch1_in_r;
	reg		[9:0] ch2_in_r;

	wire	[9:0] ch0_in_w;
	wire	[9:0] ch1_in_w;
	wire	[9:0] ch2_in_w;

	wire	ch_de;
	wire	[9:0] ch0_dec;
	wire	[9:0] ch1_dec;
	wire	[9:0] ch2_dec;

//--------------------------------------------------------------
//	design

IBUFGDS IBUFGDS_clk(.O(CLK_IN),.I(DVI_RXC_P),.IB(DVI_RXC_N));
IBUFDS IBUFDS_ch0(.O(RX0_IN),.I(DVI_RX0_P),.IB(DVI_RX0_N));
IBUFDS IBUFDS_ch1(.O(RX1_IN),.I(DVI_RX1_P),.IB(DVI_RX1_N));
IBUFDS IBUFDS_ch2(.O(RX2_IN),.I(DVI_RX2_P),.IB(DVI_RX2_N));

	assign CLK=CLK_IN;

	assign CLKx10=clk_x10;

	assign sys_rst_n=sys_rst_n_r[4];

	always @(posedge CLK_IN or negedge RESET_N)
	begin
		if (RESET_N==1'b0)
			begin
				sys_rst_n_r[4:0] <= 5'b0;
			end
		else
			begin
				sys_rst_n_r[4] <= (sys_rst_n_r[3:0]==4'hf) ? 1'b1 : sys_rst_n_r[4];
				sys_rst_n_r[3:0] <= sys_rst_n_r[3:0]+4'h1;
			end
	end

xil_dcm_x10 dcm_x10(
	.CLKIN_IN(CLK_IN), 
	.RST_IN(!sys_rst_n), 
	.CLKFX_OUT(clk_x10), 
	.CLKFX180_OUT(), 
	.CLK0_OUT(CLK_OUT), 
	.LOCKED_OUT(dcm_locked)
);

	assign CLK_LOCK=dcm_locked;

	assign rx_req=rx_req_r[3];

	always @(posedge clk_x10 or negedge RESET_N)
	begin
		if (RESET_N==1'b0)
			begin
				rx_req_r[3:0] <= 4'b0;
				rx0_r[11:0] <= 12'b0;
				rx1_r[11:0] <= 12'b0;
				rx2_r[11:0] <= 12'b0;
				rx0_out_r[9:0] <= 10'b0;
				rx1_out_r[9:0] <= 10'b0;
				rx2_out_r[9:0] <= 10'b0;
			end
		else
			begin
				rx_req_r[3:0] <= rx_req_w[3:0];
				rx0_r[11:0] <= rx0_w[11:0];
				rx1_r[11:0] <= rx1_w[11:0];
				rx2_r[11:0] <= rx2_w[11:0];
				rx0_out_r[9:0] <= rx0_out_w[9:0];
				rx1_out_r[9:0] <= rx1_out_w[9:0];
				rx2_out_r[9:0] <= rx2_out_w[9:0];
			end
	end

	assign rx_req_w[0]=CLK_IN;
	assign rx_req_w[1]=rx_req_r[0];
	assign rx_req_w[2]=(rx_req_r[1:0]==2'b01) ? 1'b1 : 1'b0;
	assign rx_req_w[3]=rx_req_r[2];

	assign rx0_w[11:0]={RX0_IN,rx0_r[11:1]};
	assign rx1_w[11:0]={RX1_IN,rx1_r[11:1]};
	assign rx2_w[11:0]={RX2_IN,rx2_r[11:1]};

	assign rx0_out_w[9:0]=(rx_req_r[2]==1'b1) ? rx0_r[9:0] : rx0_out_r[9:0];
	assign rx1_out_w[9:0]=(rx_req_r[2]==1'b1) ? rx1_r[9:0] : rx1_out_r[9:0];
	assign rx2_out_w[9:0]=(rx_req_r[2]==1'b1) ? rx2_r[9:0] : rx2_out_r[9:0];

	always @(posedge CLK or negedge RESET_N)
	begin
		if (RESET_N==1'b0)
			begin
				ch0_in_r[9:0] <= 10'b0;
				ch1_in_r[9:0] <= 10'b0;
				ch2_in_r[9:0] <= 10'b0;
			end
		else
			begin
				ch0_in_r[9:0] <= ch0_in_w[9:0];
				ch1_in_r[9:0] <= ch1_in_w[9:0];
				ch2_in_r[9:0] <= ch2_in_w[9:0];
			end
	end

	assign ch0_in_w[9:0]=rx0_out_r[9:0];
	assign ch1_in_w[9:0]=rx1_out_r[9:0];
	assign ch2_in_w[9:0]=rx2_out_r[9:0];

	assign {RX_VS,RX_HS,RX_BLU[7:0]}=ch0_dec[9:0];
	assign {RX_C1,RX_C0,RX_GRN[7:0]}=ch1_dec[9:0];
	assign {RX_C3,RX_C2,RX_RED[7:0]}=ch2_dec[9:0];

	assign RX_DE=ch_de;

dvi_data_dec dec0(
	.ch_in(ch0_in_r[9:0]),		// in    [DEC] [9:0]
	.ch_out(ch0_dec[9:0]),		// out   [DEC] [9:0]
	.ch_de(ch_de),				// out   [DEC] 

	.rst_n(RESET_N),			// in    [DEC] 
	.clk(CLK)					// in    [DEC] 
);

dvi_data_dec dec1(
	.ch_in(ch1_in_r[9:0]),		// in    [DEC] [9:0]
	.ch_out(ch1_dec[9:0]),		// out   [DEC] [9:0]
	.ch_de(),					// out   [DEC] 

	.rst_n(RESET_N),			// in    [DEC] 
	.clk(CLK)					// in    [DEC] 
);

dvi_data_dec dec2(
	.ch_in(ch2_in_r[9:0]),		// in    [DEC] [9:0]
	.ch_out(ch2_dec[9:0]),		// out   [DEC] [9:0]
	.ch_de(),					// out   [DEC] 

	.rst_n(RESET_N),			// in    [DEC] 
	.clk(CLK)					// in    [DEC] 
);

endmodule
